简介:面向嵌入式、C/C++方向求职者的面试笔试资料包,汇集Linux设备驱动、C语言经典算法、嵌入式C/C++精华文章及Linux与C面试题等核心内容,覆盖校招与社招常见考点,适合准备技术笔试、面试冲刺或系统复习的开发者学习使用。资料中既有“C语言经典算法100例”这类基础算法练习,帮助巩固编程功底;也有字符设备驱动程序框架、Linux设备驱动教学内容等进阶笔记,便于理解驱动开发核心思路;另有嵌入式C/C++语言精华文章和Linux及C面试题,可帮助读者快速梳理常考知识点与典型问题。整个RAR压缩包大小约209.69MB,目前已有289人学习下载。由于文件来自不同整理渠道,目录排列稍显分散,偶尔存在一两篇重复材料,但内容完整,不影响阅读与检索,值得作为面试备考的参考资料。 这些年我陆陆续续看过多份“嵌入式/c/c++面试笔试.rar”,自己也整理过好几版。说实话,资料从来不是稀缺资源,真正稀缺的是怎么把它拆开、消化、变成自己脑子里的东西。嵌入式C/C++方向的面试笔试,历来被大家吐槽“范围太宽”:既要考C语言指针和内存,要考C++的虚函数和智能指针,还要考操作系统、Linux内核、RTOS、甚至硬件寄存器,笔试里还有一串算法题等着你。这篇内容就是基于我这些年准备面试、也参与过不少校招社招面试的经验,把嵌入式和C/C++方向的重点逐个拆开,聊聊每一块到底考什么、为什么考、怎么准备。无论你是刚接触嵌入式的大二学生,还是准备跳槽的C++开发,都应该能从里面找到对应的复习思路。
1. 嵌入式C/C++笔面试和普通软件岗差在哪
1.1 考察范围更“杂”:从C语言到操作系统到硬件
普通软件岗的面试,核心基本固定在数据结构、算法、语言特性和少量中间件知识上。嵌入式岗位完全不是这个玩法。嵌入式软件工程师、嵌入式Linux工程师、MCU开发工程师这些岗位,考察面横跨C语言、C++、操作系统原理、Linux内核、RTOS、计算机组成原理,甚至还要现场分析一块芯片的寄存器手册。
我面试候选人的时候,习惯先问一个很基础的问题:“一个C程序从编译到运行,内存里是怎么布局的?”这道题几乎能把所有准备不充分的人筛掉。因为嵌入式场景下,内存就是命根子,你不光要知道有栈、堆、全局区、代码段,还要能解释栈溢出会引发什么现象、堆碎片化怎么处理、全局变量太多为什么会导致RAM不够用。这些问题在普通软件岗很少被问到,但在嵌入式岗位几乎是必考题。
1.2 八股文与手撕代码的双线考核
很多人把面试准备理解成“背八股文”,但实际嵌入式笔试面试是两条线并行:一条线是概念题,包括C/C++语法细节、操作系统原理、网络协议基础;另一条线是代码题,包括字符串处理、链表操作、排序算法、二叉树遍历这些经典手写题。
这两条线的关系很有意思:概念题决定你能不能进面试,代码题决定面试官愿不愿意让你过。我见过不少候选人,C++八股背得滚瓜烂熟,但让他手写一个字符串逆序,能写出来的人不到一半。还有人反过来,算法题刷得飞起,但问他volatile关键字的作用,支支吾吾说不清楚。真正稳妥的策略是两条线同时准备,用概念题构建知识体系,用代码题训练手感和思维。
2. C语言重点:指针、内存、位运算与嵌入式专属陷阱
2.1 指针与数组,面试必问的组合拳
C语言在嵌入式面试里的地位,怎么强调都不过分。它不仅是大多数MCU开发的主力语言,更是理解内存、寄存器、中断、驱动的基石。指针和数组的知识点是最高频的考题,而且喜欢组合起来考。
一个很典型的例子:
int arr[5] = {1, 2, 3, 4, 5}; int *p = arr; printf("%d %d %d\n", sizeof(arr), sizeof(p), *(p + 3));这道题考察的是数组名和指针的本质区别。数组名是首元素地址的常量,sizeof(arr)取的是整个数组占用的字节数,而sizeof(p)只是指针本身的大小。很多人搞混这两个概念,本质上是没想明白“数组名”和“指向数组首元素的指针”并不是一回事。这类题在笔试题里经常出现,而且往往藏在结构体、函数参数传递的场景里,换层皮继续考。
另一个高频考点是函数指针。嵌入式代码里回调函数、注册中断处理函数、驱动层函数表,全靠函数指针撑起来。面试官问函数指针,表面考语法,实际考你有没有写过模块化代码。能把函数指针用起来的人,写出来的驱动和中间件一般不会太差。
2.2 内存布局与栈空间:资源受限下的生死线
嵌入式环境最常见的问题是“死机”和“重启”,而这两个问题里至少有一半和内存使用有关。所以在嵌入式面试里,内存布局是重点中的重点。
C程序的内存一般分为栈区、堆区、全局区(静态区)、常量区和代码区。栈区由编译器自动管理,存放局部变量、函数调用信息,空间有限且默认不会很大;堆区由malloc/free管理,空间相对大但可能产生碎片;全局区存放全局变量和static变量;常量区存放字符串字面量和const修饰的常量;代码区存放编译后的机器码。
实际项目里我遇到过很多次栈溢出。排查手段包括查看硬件异常标志、追踪栈指针最大值、使用IDE的栈使用统计工具,但根本解决办法是估算每个任务的栈需求,留足余量。面试官问“栈空间”相关的题,往往是想看你对资源边界有没有概念。比如他问一个FreeRTOS任务的栈大小该设置成多少,不是要你给出精确数字,而是看你会不会从“函数嵌套深度、局部变量大小、中断嵌套”这几个角度去分析。
2.3 volatile、const、static、大小端这些八股常客的底层逻辑
很多人觉得volatile、const、static这些关键字是纯粹的语法题,背一背就行了。但在嵌入式面试里,这些知识点背后都有实打实的工程场景。
volatile告诉编译器不要对这个变量做优化,每次都从内存重新读取。为什么嵌入式特别爱考这个?因为寄存器映射、中断服务程序里修改的全局变量、多线程共享变量,这三个场景下如果不加volatile,优化后的代码行为完全不可控。面试官问volatile,真正想考察的是你有没有和编译器优化打过架。
const的作用不只是修饰只读变量。在嵌入式里,“只读数据放Flash而不是RAM”经常需要配合const来实现。而static关键字有两条含义:修饰局部变量时延长生命周期到整个程序运行期;修饰全局变量或函数时限制作用域到当前文件。这两条细节很多应届生搞不清。
大小端问题也值得专门准备。通信协议解析、寄存器位域定义、Flash存储数据格式,都跟大小端直接相关。面试题一般会让你写一个函数判断系统是大端还是小端:
int is_little_endian(void) { unsigned int x = 0x12345678; unsigned char *p = (unsigned char *)&x; return (*p == 0x78); }2.4 嵌入式下的“面向对象”:C语言也能写出可维护的架构
“C语言面向对象编程”这个词在业内经常被拿出来讨论。很多MCU项目受平台限制只能使用C语言,但项目复杂度又要求代码具备良好的扩展性和可维护性,这就催生了用C语言模拟面向对象设计的经典套路。
最常用的是“结构体+函数指针”的组合。比如一个按键驱动模块,可以把按键的初始化函数、扫描函数、事件回调函数封装在一个结构体里,调用方只需要持有这个结构体指针,不需要关心底层实现。这其实就是面向接口编程的思想,只是用C语言实现。
面试时如果你能主动提一嘴“我用函数指针结构体实现了多态”,并且能讲清楚为什么这么设计,通常会让面试官眼前一亮。因为大部分候选人还在纠结语法题,你已经展现出面对真实项目复杂度的思考能力。这一点在嵌入式方向的面试里很加分,建议专门准备一个小例子放在项目介绍里。
3. 操作系统与内核考点:从Linux进程模型到RTOS任务
3.1 进程、线程与上下文切换的基础题
操作系统的考察在嵌入式岗位里分为两个层次。一个是通用操作系统原理,主要针对嵌入式Linux岗位;另一个是RTOS任务调度机制,针对MCU裸机或RTOS开发。
进程和线程的区别是必考题,不能只背出“进程是资源分配的最小单位,线程是CPU调度的最小单位”这句话。面试官大概率会追问:线程切换和进程切换哪个开销大?为什么?进程间通信有哪些方式?管道、消息队列、共享内存各有什么优劣?在嵌入式Linux场景下,还可能被问到驱动开发中的信号量、完成量、等待队列这些内核机制。
上下文切换的开销分析是区分候选人水平的关键问题。线程切换只需要保存和恢复寄存器和栈指针,而进程切换还涉及虚拟地址空间的切换,这意味着要操作MMU、刷新TLB,开销明显更大。能把这个过程讲清楚,说明你对操作系统的理解不是停留在背概念层面。
3.2 同步互斥与死锁,代码题的高频出处
同步互斥是嵌入式操作系统的核心考点,也是笔试代码题的常客。信号量、互斥锁、条件变量、读写锁,这些机制要能说清各自的应用场景。
线程安全的经典问题会结合C++或C代码一起考。比如一段多线程共享变量的代码,让你指出哪里有竞态条件、应该用什么机制保护、锁的粒度怎么控制。这种题在笔试里出现频率很高,真正的难点是“锁的粒度”——锁太大,性能下降,甚至可能引入死锁风险;锁太小,临界区保护不完整,数据照样错乱。
死锁的四个必要条件(互斥、占有且等待、不可抢占、循环等待)要背熟,并且要能举出实际例子。面试官喜欢问:“如果你的项目里出现了死锁,你怎么排查?”最佳回答路径是先用调试器或日志确认所有线程的阻塞位置,再分析锁的获取顺序,最后通过统一加锁顺序或使用超时机制解决。
3.3 内存管理、MMU与中断上下文
嵌入式岗位对内存管理的理解要求比纯软件开发更高。比如虚拟内存机制,面试官可能会问:MMU的作用是什么?直接操作物理地址和通过虚拟地址访问有什么区别?在裸机环境下为什么不需要MMU?
中断和异常的区别也是高频题。中断是由硬件异步触发的,异常是CPU执行指令时同步产生的。更进阶的问题包括:中断服务程序里能不能调用printf?能不能申请动态内存?答案都是“最好不要”,因为中断上下文要求执行时间短、不能睡眠、不能依赖可能被中断打断的资源。
这类问题的考察逻辑很清晰:嵌入式开发很多时候就是在“资源受限”和“实时性要求高”两个约束下写代码,面试官需要确认你对这些约束有切身体会。
3.4 RTOS任务栈与优先级反转:实战向的深挖问题
单纯考操作系统原理还不够,很多嵌入式岗位要求候选人了解FreeRTOS、RT-Thread、uCOS等实时操作系统的任务调度机制。任务栈大小怎么估算、栈溢出检测机制的原理、任务优先级如何分配,这些都是实战向的高频问题。
优先级反转是RTOS面试里的“经典陷阱题”。问题通常是:一个高优先级任务被低优先级任务阻塞,而中优先级任务抢占了低优先级任务的CPU,导致高优先级任务迟迟无法执行,怎么办?标准解法是优先级继承或优先级天花板,FreeRTOS的互斥量支持优先级继承机制。能把这个场景讲清楚,并且提到具体RTOS的实现,面试官基本会认为你有实操经验。
4. C++核心考点:对象模型、资源管理与多线程
4.1 从构造函数到虚函数表:对象模型不可跳过
嵌入式岗位对C++的要求不像纯C++开发岗那么深,但趋势是越来越多MCU项目开始用C++,尤其是较新的芯片平台。所以C++的考察比重在明显上升,对象模型和资源管理是两大重点。
构造函数和析构函数的执行顺序是入门级考点:先基类后派生类,析构顺序相反。深拷贝和浅拷贝的区分是另一个高频考点,特别是在包含指针成员的类里,默认拷贝是浅拷贝,很容易出现double free和野指针问题。
虚函数和多态是C++面试的核心内容,围绕虚表(vtable)的问题几乎必考。每个包含虚函数的类都有一个虚表,存放虚函数地址;每个对象通过虚表指针(vptr)访问虚表。理解了这两个基本概念,再遇到析构函数为什么需要声明为virtual、构造函数为什么不能是虚函数、纯虚函数和接口类的关系这些问题,就都能推导出来。
4.2 智能指针与RAII:内存管理思想
C++相比C语言最大的优势就是RAII(资源获取即初始化)机制。智能指针是RAII思想最典型的体现,unique_ptr、shared_ptr、weak_ptr三者的区别和使用场景是面试必考。
unique_ptr独占所有权,不能拷贝只能移动;shared_ptr通过引用计数共享所有权,但要注意循环引用问题;weak_ptr是为了打破循环引用而存在的,不增加引用计数。面试官很爱问:“shared_ptr会不会导致内存泄漏?什么情况下会?”答案就是循环引用,两个对象互相持有对方的shared_ptr,引用计数永远归不了零。
嵌入式场景下使用智能指针也有特殊考量。比如中断服务函数里能否使用智能指针?答案是否定的,因为智能指针的析构可能涉及内存释放操作,可能造成不确定延迟。这种细节需要专门提一下,能体现你对嵌入式特殊约束的理解。
4.3 多线程与同步:std::thread到锁的实战
C++11之后,标准库提供了std::thread、std::mutex、std::condition_variable等线程支持库,C++多线程变成面试编程题的热门载体。高频考题包括:用锁保护共享数据的正确姿势、lock_guard和unique_lock的区别、条件变量为什么需要配合互斥锁使用、线程安全的单例模式怎么写。
一个容易翻车的点是“死锁”的编程题。比如两个线程各自持有一把锁,同时试图获取对方的锁,就形成死锁。行业内推荐的规避手段是使用std::lock函数一次性锁定多个互斥量,或者约定全局统一的加锁顺序。写多线程代码的时候,把锁的获取顺序作为一种全局约束去执行,是最简单有效的策略。
4.4 STL容器与迭代器失效
STL容器也是C++面试的常客,vector、list、map、unordered_map各自的底层实现和适用场景要能说清楚。vector的扩容机制是高频考点:当容量不足时,会分配一块新内存、移动原元素、释放旧内存,扩容倍数一般是1.5到2倍。
迭代器失效题目在笔试里很常见。比如遍历vector时执行erase操作,返回值应该是什么?如果使用范围for循环在遍历时修改容器,为什么可能崩溃?这些细节都源自容器底层实现的内存管理逻辑。
嵌入式C++开发还需要额外关注STL在新平台上的适配问题。一些MCU的工具链对STL支持不完整,异常机制也可能默认关闭,面试官可能会问你怎么取舍——这时候“不完全依赖STL,手写简单的容器或使用静态分配方案”通常是可接受的回答方向。
5. 笔试算法题:从字符串逆序到AVL树,一道一道过
5.1 笔试题型的三个层次
嵌入式/C++笔试里的算法题,难度跨度很大。第一层是基础语法题,比如字符串逆序、冒泡排序、字符统计,主要考察代码基本功;第二层是数据结构题,比如链表反转、栈实现队列、二叉树遍历;第三层是算法设计题,比如动态规划、贪心法。
很多人在第一层就翻车。“字符串逆序”看起来简单,但要用C语言不用库函数实现,还要考虑原地逆序,能一次写对的人不多。冒泡排序在嵌入式笔试里出现频率也很高,因为很多面试官想考察的是“你能否写出无bug的标准代码”,而不是你是否会用sort函数。
训练基本功,我建议放弃编程助手,纯手写。面试时的手写代码是在白纸或在线编辑器上进行的,没有自动补全、没有语法检查,平时不练习手写,现场会非常难受。
5.2 常考数据结构:链表、二叉树、AVL树与字典树
链表操作题是笔试的常青树,因为C语言的指针和链表天然契合。高频题包括:单链表反转、判断链表是否有环、找到链表中间节点、合并两个有序链表。这些题难度不大,但考察的是连续的内存分析和边界条件处理能力。
二叉树题目也不可绕过,层次遍历、前序中序后序的递归与非递归实现、求二叉树深度、判断对称二叉树,属于基本操作。热词里提到的AVL树和字典树(Trie)属于加分项,AVL树需要掌握LL、RR、LR、RL四种旋转,字典树需要理解它的节点结构和典型应用场景(单词前缀匹配、敏感词过滤、IP路由表)。
笔试阶段通常不会要求直接手写完整的AVL树和字典树代码,但选择题、填空题会考原理和复杂度,面试中也可能让你口述实现思路。
5.3 ACM模式的输入输出问题:很多人挂在环境上
必须单独提醒:嵌入式C/C++笔试通常采用ACM模式,要求自己处理输入输出。这不是LeetCode那种核心代码模式,函数参数都给你传好了,你只需要实现逻辑。笔试时,你需要自己写完整程序,包括读取多个测试用例、判断输入是否结束。
一个典型场景:输入多行整数,每行两个数,输出它们的和,直到遇到文件结束标志。
#include <stdio.h> int main() { int a, b; while (scanf("%d %d", &a, &b) != EOF) { printf("%d\n", a + b); } return 0; }C++写法类似:
#include <iostream> using namespace std; int main() { int a, b; while (cin >> a >> b) { cout << a + b << endl; } return 0; }这种题本身没有难度,但每年都有候选人因为不熟悉输入输出处理而挂掉。建议备战阶段就把本地环境配好,VSCode配置好C/C++调试环境是基本功,所有练习都用ACM模式写,用实际测试用例验证,到笔试现场才不慌。
5.4 刷题规划:刷多少才够稳
不需要追求爆炸题量,更不要盲目刷难题。嵌入式方向的笔试题难度整体低于互联网大厂核心算法岗,最常见的是数组、字符串、链表、栈、队列、二叉树的基础题,再加少量动态规划。
我的建议是分三个阶段。第一个阶段,精刷基础题40道,覆盖上述数据结构的基础操作;第二个阶段,按类型刷LeetCode热题Hot 100的简单和中等题型,大约30道;第三个阶段,练近两年的嵌入式企业笔试真题,感受出题风格。完成这三步,基本能覆盖90%以上的嵌入式C/C++笔试。
6. 从资料到offer:路线、项目与现场表达
6.1 分阶段的备考时间线
面试准备最怕的是“一把抓”。C语言没复习透就去看算法,算法还没练熟又去啃C++,最后哪块都是半吊子。我建议按时间划分成四个阶段:
第一个阶段(基础期,2周):主攻C语言和操作系统原理。目标是能把指针、内存、结构体、链表、进程线程、同步互斥这些概念讲清楚,配合少量C语言练习题。
第二个阶段(进阶期,2周):主攻C++对象模型、智能指针、STL、多线程。配合C++面试题练习,整理自己的“八股文笔记”。
第三个阶段(算法期,2周):每天2到3道经典代码题,重点覆盖字符串、链表、二叉树、排序、动态规划,全程ACM模式。
第四个阶段(冲刺期,1周):整理简历项目,准备项目深挖问题,做几场模拟面试,查漏补缺。
一共7周,每天保证2小时以上。这套计划我见证过很多人执行,只要不打折扣,效果通常很明显。
6.2 简历上的嵌入式项目怎么经得起追问
简历上的项目经历是面试官深挖的主战场。嵌入式方向的项目最好体现完整链路:用什么MCU或SoC、开发环境是什么、实现了哪些功能模块、遇到了什么技术难点、怎么解决的、最后效果如何。
举一个典型的项目描述:“基于STM32F407的智能环境监测系统,实现温湿度、空气质量数据的采集、LCD显示和Wi-Fi上传。负责传感器驱动编写、RS485通信协议解析、FreeRTOS多任务调度设计。实际调试中解决了传感器数据采集不稳定的问题,原因是I2C通信信号干扰,最终通过调整通信速率和增加滤波逻辑解决。”
这种描述好在有硬件、有软件、有协议、有系统、有难点、有结果。面试官追问的时候,每一个点都有东西可讲。反之,如果只写“熟练掌握C语言、熟悉嵌入式开发流程”,面试官根本不知道从何问起,也就很难给你打高分。
6.3 面试现场的表达习惯与心态
嵌入式面试的技术问题,回答模式通常采用“结论先行、分层展开、举例收尾”三步。比如面试官问“进程和线程的区别”,先一句话给出结论“进程是资源分配的基本单位,线程是CPU调度的基本单位”,然后分别展开说明各自的资源构成和调度方式,最后举一个Linux或FreeRTOS里的实际例子,既有条理又显得实战经验丰富。
遇到算法题,先不要急着写代码。先把思路讲出来:“我先用暴力法解决,然后分析复杂度,再考虑是否可以用双指针或动态规划优化。”面试官更看重思考过程,而不是最终答案。如果卡住了,主动说出当前的思考卡点,远比沉默到底好得多。
6.4 拿到“面试笔试.rar”之后怎么用
最后回到你这个压缩包。很多人下载完就扔在网盘里吃灰,其实这类资料的正确用法是“拆解”而不是“收藏”。
把里面所有的面试题按专题归类,比如C语言、C++、操作系统、算法、网络、硬件,每个专题做一份自己的笔记,每题先自己尝试回答,再对照资料里的答案修正。回答不出来的题目就是你的知识盲区,标记成重点,回到对应的书籍或文档里精读。电子资料里经常有一些项目实战代码,不要只看,动手编译一遍,改几个功能需求重新实现,印象会深得多。
到冲刺阶段,把这些笔记压缩成几页“话术卡”,每个知识点用两三句话能说清楚。真正到了面试现场,你脑子里装的不再是几百道题,而是一张逻辑清晰的知识网。到这个时候,“嵌入式/c/c++面试笔试.rar”的意义才真正发挥出来——它是你备考过程中的导航图,而不是终点。
我自己备考时最后一周做的事特别简单:把所有知识点按章节抄在一张A4纸上,每天睡前像过电影一样过一遍,说不清楚的地方第二天立刻查资料补齐。这个方法看着土,但在高强度面试季真的帮我稳住了阵脚。嵌入式这个方向,范围宽、深度也够,任何资料都替代不了你动手写代码和反复思考的过程,祝大家都能拿到满意的offer。
本文还有配套的精品资源,点击获取