尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

嵌入式软件笔试高频考点解析:C语言、操作系统与Linux全覆盖

嵌入式软件笔试高频考点解析:C语言、操作系统与Linux全覆盖 每年秋招季总有一批准备投嵌入式软件岗的同学到处翻往年的笔试真题。顺丰科技2019秋招这套嵌入式软件开发工程师客观题虽然年份久了一点但嵌入式岗位考察的底层知识相当稳定C语言、操作系统、数据结构、计算机组成原理、网络这几座大山基本没变过。我拿到这份题集重新梳理了一遍发现里面的考点放到现在依然有很强的指向性很适合作为一轮系统复习的摸底清单。这篇文章就来逐块拆解这套题的考察逻辑结合我自己的复习和面试经验讲清楚每类题背后的知识点、容易踩的坑以及怎么把题目延伸到面试环节去准备。1. 整体设计与考察范围拆解客观题作为一个笔试环节设计的核心目标是用有限的时间筛出基础扎实、思维严谨的人。所谓客观题典型形态就是单选、多选、判断和少量填空题。嵌入式软件开发岗位面对的工作内容是驱动开发、系统移植、应用层逻辑实现、性能优化因此笔试的覆盖面必然横跨整个CS核心知识体系。从这套2019年的题集来看考察范围可以大致归成六类C语言与内存管理指针、数组、结构体对齐、关键字语义、内存布局。数据结构与算法基础链表、栈、队列、树、复杂度分析。操作系统原理进程线程、调度、同步互斥、死锁、内存管理。计算机组成原理大小端、位域、中断、寄存器、Cache。网络基础TCP/IP分层、三次握手、IP地址基础。Linux与嵌入式基础常用命令、交叉编译、驱动模型初步、文件系统。这个分布不是顺丰独有的而是嵌入式软件岗位笔试的通用模板。原因很直接嵌入式开发本质上是在资源受限的硬件环境里写软件任何一个底层知识点没吃透都可能在生产环境酿成线上问题。比如一个结构体对齐的误判会导致通信协议解析错位一个对volatile的忽视会让中断共享变量在多线程中出现野值。笔试看起来在考概念实际上是在筛掉那些只背API、不懂原理的人。我对这份题集的整体评价是难度中等偏上但胜在范围广、细节深。没有特别偏门的硬件电路题也没有特别艰深的算法题重点放在基础是否扎实和有没有踩过坑这两个维度。这两点正是嵌入式软件工程师日常工作最需要的素质。2. 核心知识点拆解C语言与内存管理2.1 指针与数组的关系这套题里指针和数组几乎必考常见出法有这几种sizeof一个数组名和sizeof一个指针变量的区别。数组名作为函数参数传递后退化为指针。二维数组的指针偏移计算。char *p与char p[]的区别。我当年复习时有个体会很多同学做错不是不知道定义而是没有在头脑中建立内存图景。比如下面这个典型例子char str[] hello; char *p hello; printf(%d %d\n, sizeof(str), sizeof(p));在32位系统上str是数组sizeof(str)是65个字符加一个结尾符p是指针sizeof(p)是4。这个题几乎每年笔试都会出现但错误率一直很高。原因就是很多人把数组和指针混为一谈。数组名在大多数表达式中会退化为指向首元素的指针但在sizeof和操作符下不退化。这一点必须记牢因为嵌入式面试官极爱追问。实际工程里指针数组和数组指针也容易搞混。int *a[10]是指针的数组int (*a)[10]是数组的指针。在解析通信协议帧、处理二维矩阵时这两种类型用错直接编译报错或者内存越界。2.2 结构体字节对齐与内存布局结构体对齐是嵌入式笔试的保留节目因为它在实际项目中的影响太明显了。通信协议、硬件寄存器映射、文件头结构全都依赖结构体的内存布局。题集里这类题一般会给一个结构体然后问sizeofstruct example { char a; int b; char c; };在32位系统、默认4字节对齐下a占1字节填充3字节b占4字节c占1字节再填充3字节总大小12字节。如果我把成员顺序换一下struct example2 { char a; char c; int b; };同样三个成员大小却是8字节。这里面的核心规则就一句话每个成员的偏移量必须是其自身对齐数的整数倍结构体总大小必须是最大对齐数的整数倍。嵌入式工程师经常手动调整成员顺序来压缩结构体体积这在资源紧张的MCU上非常实用。实际嵌入式场景里还有更进阶的玩法用#pragma pack(1)或__attribute__((packed))来取消对齐让结构体紧凑排列通常用于网络协议或者存储格式。但这会带来一个问题非对齐访问在某些架构上会触发硬件异常或者降低访问效率。笔试可能不会考到这么深但面试时聊到这里能把这个代价说出来会很加分。2.3 大小端模式考察大小端的题目在这套题里也有出现。大端模式是高位字节存低地址小端模式是低位字节存低地址。x86 是小端ARM 默认也是小端可以切换而网络字节序统一是大端。常见的代码题是这样unsigned int x 0x12345678; unsigned char *p (unsigned char *)x; printf(%x %x %x %x\n, p[0], p[1], p[2], p[3]);在小端机器上输出是78 56 34 12。很多新手第一次在这里翻车是因为直觉上认为内存里的顺序应该和书写顺序一致。在实际开发中MCU 和传感器之间通过 SPI/I2C 通信协议里明确规定字节序如果主控和从机字节序不一致读出来的数据就会面目全非。有一个判断大小端的经典程序也需要掌握int is_little_endian(void) { int x 1; return *(char *)x; }返回1是小端返回0是大端。这个函数看起来简单但里面包含了指针强转、内存视图切换两个核心概念面试官喜欢让候选人现场写。2.4 位操作与位域嵌入式开发离不了位操作笔试常考的是用位运算实现特定功能将某位置1x | (1 n)。将某位清0x ~(1 n)。翻转某位x ^ (1 n)。取某位的值(x n) 1。这些操作在寄存器配置里最常用。例如操作 GPIO 的输出寄存器要单独把第5引脚拉高而不影响其他引脚就可以这样做。还有一类题目考位域struct status { unsigned int a : 1; unsigned int b : 3; unsigned int c : 4; };位域在嵌入式里常用于硬件寄存器定义比如把一个32位寄存器按功能拆成多个字段。但面试官心里很清楚位域是跨编译器行为最容易不一致的特性之一位域的内存分配顺序、对齐方式在不同编译器上可能不同因此在可移植性要求高的代码里很多团队宁可自己写宏定义加位运算也不用位域。答题时能主动提到这一层会让面试官觉得你不仅有知识还有工程判断力。2.5 关键字const、static、volatile这组关键字是嵌入式面试出现频率最高的内容尤其是在选择题里用来考概念辨析。const修饰变量的含义是该变量在作用域内不可被修改。但要注意const修饰的是指针本身还是指针指向的内容。我在复习时总结了一个口诀const在*左边修饰指向的内容在*右边修饰指针本身。static有两个核心作用修饰局部变量时变量生命周期延长到程序结束且只初始化一次修饰函数和全局变量时限制其作用域在当前文件。在嵌入式项目中static局部变量常用于函数内需要保持状态值的场合比如按键扫描的去抖计数器。volatile是嵌入式里最重要的关键字之一笔试里考的是告诉编译器该变量可能被外部意外修改禁止将其优化到寄存器中每次都必须从内存地址读取。它主要用来修饰三类东西硬件寄存器、中断服务程序中修改的全局变量、多线程间共享的变量。这里有一个经典陷阱题int flag 0; void isr(void) { flag 1; } while (flag 0) { // 等待中断 }如果flag没有加volatile编译器在优化时可能将flag的读取操作提到循环外导致循环永远出不来。这就是笔试中经常出现的考察点。在软件上很多线上问题最终定位到missing volatile都是血泪教训。3. 操作系统、数据结构与计组考点精讲3.1 进程与线程概念辨析这套题里操作系统部分占了不小比例进程和线程的区别就是必考内容。典型问题包括进程是资源分配的基本单位线程是CPU调度的基本单位。同一个进程下的线程共享地址空间、文件描述符但各有独立的栈和寄存器上下文。进程之间互相隔离通信需要借助IPC。嵌入式里还有一个容易被轻视的概念叫并发与并行的区别并发是多个任务在宏观上同时推进但微观上可能交替执行并行是多个核心在同一个时刻真正同时执行多个任务。笔试会考概念面试时则可能让你结合一个实际的双核MCU项目谈如何分配任务。线程间同步也是重点。互斥锁、信号量、条件变量、自旋锁的使用场景几乎是嵌入式软件笔试的固定题组。这里我给出一个速查表方便复习时对照同步机制适用场景注意事项互斥锁保护临界区防止多个线程同时写注意死锁避免嵌套加锁信号量资源计数、任务同步二值信号量和互斥锁不完全等价条件变量等待某个条件满足再继续必须配合互斥锁使用自旋锁临界区极短且不会睡眠会忙等长临界区不适合3.2 调度算法与死锁操作系统调度算法的选择题考察的核心是理解各算法的出发点和代价。先来先服务看重公平性但短任务可能等很久短作业优先能降低平均等待时间但长任务可能饿死时间片轮转保证响应性但切换开销大优先级调度实时性好但需要处理优先级反转。嵌入式实时操作系统里最常见的是优先级抢占式调度FreeRTOS、RT-Thread、uC/OS 都采用这种策略。题目如果给你三个任务的优先级和CPU时间让你计算某个任务的完成时间你需要先画出调度时序图再逐步计算。这种题没有技巧多练几遍就熟了。死锁的四个必要条件——互斥、持有并等待、不可剥夺、循环等待——也是必背内容。实际面试时更喜欢让你讲讲实际项目里怎么避免死锁。我自己的经验是能不用锁就别用锁能用原子操作解决的就用原子操作必须用锁时保持一致的加锁顺序并配合超时机制。3.3 链表、栈、队列与二叉树数据结构在嵌入式笔试中考察范围不大但都是最常用的那几样。链表题几乎必考尤其是单链表反转、判断链表是否有环、合并两个有序链表。这些题目可以直接在LeetCode上刷但嵌入式岗位一般不会考太偏的题把基础题刷熟就够。还有一个高频考点是栈和队列的互相实现。两个栈模拟一个队列或者两个队列模拟一个栈这种题考察的是对数据结构的本质理解。另外表达式中缀转后缀也是经典题有些编译器或计算器模块里会用到。二叉树部分主要考察遍历方式前序、中序、后序、层序以及根据两种遍历序列推导树结构。嵌入式开发里二叉树用得不算多但红黑树是内核和很多RTOS定时器的底层实现所以面试官有时候会问树的基本概念。时间复杂度分析题也经常出现。比如链表在头部插入是O(1)在尾部插入要遍历到末尾是O(n)有序数组二分查找是O(logn)但如果插入数据是O(n)。不要死记结论要会从实现角度推导。3.4 中断、寄存器与Cache计算机组成原理在嵌入式笔试里主要考察中断系统和存储层次。中断相关的关键概念中断向量表、中断优先级、中断服务函数不能执行耗时操作、需要处理临界区保护。有一类选择会给一个场景让你判断哪些操作不能在ISR里做答案通常是打印、动态内存分配、长时间的延时。中断嵌套与抢占也是常考点。在Cortex-M系列处理器里NVIC支持中断嵌套高优先级中断可以打断低优先级中断。题目如果问你关中断的粒度问题核心考量是关中断时间太长会导致实时性下降太短又保护不了临界区。Cache的考察点集中在局部性原理、Cache命中率、写回与写直达策略。嵌入式工程师在做性能优化时经常需要考虑数据和指令在Cache中的布局。另外volatile与硬件寄存器也在这里再次交汇。映射到地址空间的寄存器必须用volatile声明防止编译器优化。笔试里的形式通常是给一段内存映射寄存器操作代码让你判断哪里有问题。4. 网络、Linux与嵌入式实战方向4.1 TCP/IP 基础与三次握手TCP/IP协议栈在嵌入式网络开发中是绕不开的。选择题经常出现TCP三次握手的状态转换、第四次挥手为什么要TIME_WAIT。三次握手的细节要能默写客户端发送SYN服务端回复SYNACK客户端再回复ACK。还有一个常见变体为什么需要三次而不是两次核心原因是防止失效的连接请求突然到达服务端导致资源浪费。四次挥手里面有一个高频追问为什么客户端最后要等2MSL原因有两点一是保证最后一个ACK能到服务端万一丢了可以重传二是让旧连接的所有报文在网络中消失避免干扰新连接。这个点如果面试时能答出两层含义就很完整了。IP地址相关的计算题比如给定IP和子网掩码求网络号、广播地址这类题偶尔出现。计算方法很简单IP和掩码按位与得到网络号主机位全置1得到广播地址。4.2 Linux 常用命令与文件系统嵌入式开发和Linux密不可分笔试会考常用命令的用法。比如ls列出文件cd切换目录pwd显示当前路径。cp复制mv移动或重命名rm删除。cat查看文件内容head/tail查看文件头部/尾部grep搜索文本。find查找文件chmod修改权限ps查看进程。top查看系统资源df/du查看磁盘使用情况。ifconfig/ip addr查看网络接口ping测试连通性。tar打包解包make编译工程。有一类题目会问grep和find的区别grep在文件内容中搜索文本find按文件名或属性查找文件。这个区分在实际使用中很常见但在笔试中被单独拿出来点名时还是有一批人会混淆。文件系统部分常考的是嵌入式Linux里常用的文件系统类型jffs2、yaffs2、ubifs是Flash上常用的日志型文件系统ext4是PC上标准的磁盘文件系统。题集的考察思路通常是让你根据读写均衡、掉电安全、NAND Flash这些关键词选合适的文件系统。4.3 交叉编译与驱动基础嵌入式岗位的笔试有一个区别于纯后端开发的特色交叉编译和驱动模型。交叉编译考的是概念比如arm-linux-gnueabihf-gcc在x86主机上编译出ARM架构的程序这个编译过程叫交叉编译。题目会问为什么不能直接在ARM板子上编译——因为板子性能弱、工具链齐全度差、存储空间有限。驱动部分的题目主要看有没有基础概念。字符设备、块设备、网络设备的区别platform总线的作用设备树文件的作用。这些题目如果没做过Linux驱动开发可能只能靠背概念。但从我的经验看笔试考得不会太深能把open、read、write、ioctl这些系统调用到驱动函数的流转路径讲清楚就已经能胜过绝大多数候选人了。4.4 常见笔试代码题解决一个实际场景有时候客观题会结合代码片段来考。比如下面这种int func(void) { static int count 0; count; return count; }连续调用三次返回值分别是1、2、3。因为static局部变量只初始化一次存储于静态存储区。还有一类考察位操作和宏定义的组合#define SET_BIT(x, n) ((x) | (1 (n))) #define CLEAR_BIT(x, n) ((x) ~(1 (n)))题目往往以选择题形式出现要求判断宏在参数为表达式时是否有副作用。比如SET_BIT(a, i)里i会被展开两次产生未定义行为。这是宏定义里最经典的坑考察的是对预处理机制的理解深度。5. 常见问题与备考避坑技巧5.1 高频易错点复盘结合这套题集和这些年秋招观察到的普遍问题我把高频易错点整理成了下面的表格复习时可以直接对照检查易错点正确的理解常见错误sizeof数组名返回整个数组占用的字节数误认为是指针大小结构体对齐总大小要满足最大对齐数的整数倍漏算尾部填充字节volatile禁止编译器优化到寄存器认为只是普通修饰符数组名作参退化为指向首元素的指针以为仍保留数组长度信息大小端小端低位字节在低地址受到书写顺序干扰TCP挥手TIME_WAIT确保最后一个ACK可靠忽略2MSL的语义static局部变量生命周期为程序运行期误以为作用域也全局化5.2 多选题选错一个就全错顺丰这套题里有多选题多选题的残酷之处在于选错一个就全错所以策略与单选题不一样。我的建议是遇到不确定的选项宁可少选不要冒险多选。如果是拿不准的选项根据概念包含关系去判断。比如下列关于栈的描述正确的是只要有一个选项描述的是队列特性它肯定错。多选题里最阴险的考法是把两个概念放在一起混淆。比如一个选项说数组可以在O(1)时间内删除中间元素这个选项明显是链表特性的错位。做这类题的关键是对每个选项单独判断而不是靠排除法找正确答案。5.3 刷题之外把知识点串成体系我不建议纯粹靠刷题来通过嵌入式笔试因为客观题考察的知识点虽然固定但每年的问法和组合方式都在变。真正稳妥的复习方式是把知识点连成网比如C语言的内存管理可以和操作系统的内存管理联系起来复习结构体对齐可以延伸到大端小端和通信协议解析volatile可以串联到中断服务和多线程同步。我复习时习惯画一张思维导图从内存出发延伸到栈、堆、静态存储区、寄存器映射再延伸到指针、数组、结构体、位域、volatile、const。从执行出发延伸到进程线程、任务调度、中断、系统调用、驱动模型。这样笔试考任何一个点我都能快速定位到它所属的知识群。5.4 嵌入式学习路线的建议结合这套题集的覆盖面给正在准备秋招的同学一个学习路线参考。如果是从零基础开始顺序可以这样安排先打C语言基础做到能用指针操作内存理解数组和结构体的内存布局。学数据结构重点线性表和二叉树能手写链表反转和树的遍历。学操作系统原理理解进程线程、调度、同步互斥、死锁。学计算机组成原理重点中断、存储层次、汇编基础。学Linux基础掌握常用命令和文件系统概念。选一块开发板做实战推荐STM32或全志/瑞芯微平台的Linux开发板跑通一个带中断、定时器、通信接口的综合项目。有余力再深入Linux驱动理解字符设备框架和设备树。这套路线走下来刷上一两套真题集笔试通过率会显著提升。很多同学只刷题不补体系遇到原题能答对换一个问法就懵这就是知识不成网导致的。6. 从笔试到面试如何把客观题转化为加分项笔试结束往往只是第一关紧接着的面试才是真正区分高下的地方。我的体会是客观题里出现的知识点面试官极有可能顺着追问。比如笔试里考了结构体对齐面试官可能让你现场设计一个通信协议帧结构问你怎么安排成员顺序、要不要加CRC、怎么处理字节序。我在这里分享一个万能思路把笔试知识点翻译成项目经历。简历上写熟悉Linux驱动开发的人很多但能讲清楚设备树里如何描述一个SPI设备的人就少很多。面试官想听到的不是名词而是你对取舍和原理的理解。举例来说如果你在笔试里遇到了大小端的题那么面试时你可以主动说我在项目里用I2C读取传感器数据时发现传感器的输出是大端格式而MCU是小端所以我在驱动里做了一次字节交换处理并且封装成了统一的接口。 这样一段话就把大小端这个知识点从会做题提升到了有实战经验。再举一个例子笔试题里常考volatile面试时你可以结合一个实际的BUG来谈某个变量在中断里修改主循环里没有加volatile导致优化后读取不到新值排查了一整个下午才发现是编译器优化的问题。这种真实经历远比背书上的定义更能打动面试官。还有一个很多同学会忽略的点客观题里的数据结构题面试时可能会要求现场手写代码。链表反转、判断环入口、两个栈实现队列这些题务必做到能脱稿手写且保证语法正确。我的习惯是面试前在草稿纸上反复默写这些经典代码写到条件反射的程度。最后提醒一句笔试中做错的原题也要复盘。我当时把做错的每道题都整理成了一个错题本在旁标注错误原因和正确的推导过程。秋招后期我会翻看这些记录很多易错点会在不同公司的题目里反复出现比如结构体对齐、进程和线程的区别、TCP的TIME_WAIT几乎每家公司都考。这套2019年的题集虽然年份有些久但嵌入式岗位的考察内核却没怎么变。把基础打扎实、把错题复盘到位、把知识点串成网络秋招笔试这一关并没有想象中那么难。希望这篇文章能帮你理清复习思路少走一些弯路。
返回列表