嵌入式软件面试高频题汇总:进程线程、C++、网络、Linux 与单片机
- 时间
- 2026-09
- 来源
- 牛客网
《面试题目》
简历与项目准备
- 找单片机方向,简历上应该写什么类型的项目?
- 找嵌入式 Linux 应用开发,可以写驱动项目吗?需要几个应用层项目?
- 找嵌入式 Linux 驱动开发,要不要补一个应用层项目?
- 项目数量写几个合适?确实没有项目怎么办?
第一章 进程与线程
- 什么是进程、线程,彼此有什么区别?
- 多进程、多线程的优缺点?
- 什么时候用进程,什么时候用线程?
- 多进程、多线程同步(通讯)的方法有哪些?
- 进程的空间模型是什么样的?
- 进程线程的状态转换图,什么时候阻塞、什么时候就绪?
- 父进程、子进程的关系以及区别?
- 什么是进程上下文、中断上下文?
- 一个进程可以创建多少线程,和什么有关?
- 什么是线程同步和互斥?
- 线程同步与阻塞的关系?同步一定阻塞吗?阻塞一定同步吗?
- 并发、同步、异步、互斥、阻塞、非阻塞怎么理解?
- 孤儿进程、僵尸进程、守护进程的基本概念?
- 如何创建守护进程?
- 正确处理僵尸进程的方法有哪些?
第二章 C/C++
- new 和 malloc 的区别?
- malloc 的底层实现?
- 在 1G 内存的计算机中能否 malloc(1.2G)?为什么?
- 指针与引用的相同和区别?如何相互转换?
- C 语言检索内存的情况、内存分配的方式有哪些?
- extern “C” 的作用?
- 头文件声明时加 extern、定义时不要加,为什么?
- 函数参数压栈顺序,即关于 __stdcall 和 __cdecl 调用方式的理解?
- 重写 memcpy() 函数需要注意哪些问题?
- 数组到底存放在哪里?
- struct 和 class 的区别?
- char 和 int 之间的转换?
- static 的用法(定义和用途)?
- const 常量和 #define 的区别(编译阶段、安全性、内存占用等)?
- volatile 的作用和用法?
- 有常量指针、指针常量、常量引用,为什么没有引用常量?
- 没有指向引用的指针,但有指针的引用,为什么?
- C/C++ 中变量的作用域?
- C++ 中类型转换机制有哪些?各适用什么环境?dynamic_cast 转换失败时会出现什么情况?
- 继承和虚继承?
- 多态的类,内存布局是怎么样的?
- 被隐藏的基类函数如何调用?子类如何调用父类的同名函数和父类成员变量?
- 多态实现的三个条件、实现的原理?
- 对拷贝构造函数、深浅拷贝的理解?拷贝构造函数的作用及用途?什么时候需要自定义拷贝构造函数?
- 析构函数可以抛出异常吗?为什么不能抛出异常?除了资源泄露,还有其他需要考虑的因素吗?
- 什么情况下会调用拷贝构造函数(三种情况)?
- 析构函数一般写成虚函数的原因?
- 构造函数为什么一般不定义为虚函数?
- 什么是纯虚函数?
- 静态绑定和动态绑定的介绍?
- C++ 所有的构造函数有哪些?
- 重写、重载、覆盖的区别?
- 成员初始化列表的概念,为什么用成员初始化列表会快一些?
- 如何避免编译器进行的隐式类型转换(explicit)?
第三章 网络编程
- TCP、UDP 的区别?
- TCP、UDP 的优缺点?
- TCP、UDP 的适用场景?
- TCP 为什么是可靠连接?
- 典型网络模型有哪些?简单说说。
- HTTP 1.1 和 HTTP 1.0 的区别?
- URI(统一资源标识符)和 URL(统一资源定位符)之间的区别?
- 什么是三次握手?
- 为什么三次握手中客户端还要发送一次确认?可以二次握手吗?
- 为什么服务端易受到 SYN 攻击?
- 什么是四次挥手?
- 为什么客户端最后还要等待 2MSL?
- 为什么建立连接是三次握手,关闭连接却是四次挥手?
第四章 常见算法
- 各种排序算法的时间空间复杂度、稳定性?
- 各种排序算法什么时候有最好情况、最坏情况(尤其是快排)?
- 冒泡排序、选择排序、插入排序、希尔排序、归并排序、快速排序分别怎么写?
- 快排的 partition 函数与归并的 merge 函数?
- vector 和 list 的异同?
- vector 内存是怎么增长的?vector 的底层实现?
- vector 和 deque 的比较?
- 为什么 STL 里面有 sort 函数,list 里面还要再定义一个 sort?
- STL 底层数据结构实现?
- 利用迭代器删除元素会发生什么?
- map 是如何实现的,查找效率是多少?
- 几种模板插入的时间复杂度?
第五章 Linux 操作系统
- Linux 内核的组成?
- 用户空间与内核通信方式有哪些?
- 系统调用 read()/write(),内核具体做了哪些事情?
- 系统调用的作用?
- 内核态、用户态的区别?
- bootloader、内核、根文件系统的关系?
- Bootloader 多数有两个阶段的启动过程,说说看。
- Linux 的内核是由 bootloader 装载到内存中的吗?
- 为什么需要 BootLoader?
- Linux 内核同步方式总结?
- 为什么自旋锁不能睡眠,而在拥有信号量时就可以?
- Linux 下检查内存状态的命令有哪些?
- 大小端的区别以及各自的优点,哪种时候用?
- 一个程序从开始运行到结束的完整过程(四个过程)?
- 什么是堆、栈、内存泄漏和内存溢出?
- 堆和栈的区别?
- 死锁的原因、条件?如何创建一个死锁,以及如何预防?
- 硬链接与软链接的区别?
- 虚拟内存是什么?虚拟地址与物理地址如何转换?
- 计算机中,32bit 与 64bit 有什么区别?
- 中断和异常的区别?
- 中断怎么发生,中断处理大概流程?
- Linux 操作系统挂起、休眠、关机相关命令?
- 数据库为什么要建立索引,以及索引的缺点?
第六章 单片机
- CPU、内存、虚拟内存、磁盘/硬盘的关系?
- CPU 内部结构?
- ARM 结构处理器简析。
- 波特率是什么,为什么双方波特率要相同,高低波特率有什么区别?
- ARM 和 DSP 有什么区别?
- ROM、RAM 的概念浅析。
- IO 口工作方式:上拉输入、下拉输入、推挽输出、开漏输出?
- 扇区、块、页、簇的概念?
- 处理器读内存的过程中,CPU 核、cache、MMU 如何协同工作?画出它们之间的关系示意图说明。
- 总线接口 USART、I2C、USB 的异同点(串/并、速度、全/半双工、总线拓扑等)?
- 什么是异步串口和同步串口?
- I2C 时序图?
《参考解析》
- 进程与线程的区别:进程是资源分配的基本单位,有自己的地址空间、文件描述符表和页表;线程是调度的基本单位,同一进程内的线程共享地址空间与打开的文件,只独占栈和寄存器上下文。因此线程切换不用换页表、开销小,但一个线程把堆写坏整进程一起崩;要隔离性和稳定性就用多进程,要高并发共享数据就用多线程。
- 多进程与多线程的同步方式:进程间有无名管道、有名管道、消息队列、共享内存加信号量、信号和 socket,其中共享内存最快但要自己做同步;线程间有互斥锁、条件变量、读写锁、信号量和自旋锁。选型的点是临界区多长——长临界区用互斥锁让出 CPU,极短的临界区用自旋锁避免切换开销;条件变量要配一把互斥锁用,且唤醒前后都要判条件避免惊群和虚假唤醒。
- 僵尸进程、孤儿进程、守护进程:子进程先退出而父进程没 wait,进程表项留着就是僵尸,处理办法是父进程及时回收或忽略 SIGCHLD 后 wait 兜底;父进程先退出、子进程被 init 收养就是孤儿进程,本身无害。守护进程要 fork 后 setsid 脱离控制终端,再 fork 一次确保不是会话首进程、免得重新拿到终端,然后重定向标准输入输出、切换工作目录、重置 umask。
- new 与 malloc 的区别,malloc 的底层实现:new 是运算符,分配完会调构造函数,失败抛 bad_alloc,内存大小由编译器推导;malloc 是库函数,返回 void*,失败返回 NULL,需要自己算字节数并强转。malloc 底层用 brk 在堆顶扩展小块内存、用 mmap 映射大块(超过 mmap 阈值),空闲块由 ptmalloc 用 bin 和空闲链表管理,释放时能合并相邻空闲块以减少碎片。
- 三次握手为什么不能两次,为什么挥手要四次:两次握手时服务端发出确认就认为连接建立,但那个 ACK 可能来自一个延迟到达的旧连接请求,服务端会白白开一条连接等数据。第三次确认让客户端也确认了服务端的收发能力,双方才同步完序号。挥手是四次,因为 TCP 是全双工,一端的 FIN 只表示自己没数据要发了,对方收到后先回 ACK,等自己数据也发完再发 FIN,中间这两步不能合并。
- TCP 靠什么保证可靠:数据切成段并带序号,接收端用累积确认回复,发送端配超时重传;滑动窗口做流量控制,接收窗口为 0 时靠持续探测避免死等;发送端按慢启动、拥塞避免、快重传快恢复调整速率;报文头有校验和,加序号一起挡住重复与乱序。