嵌入式面试C语言真的很重要
我在秋招和春招加起来面了 20 多家大厂嵌入式岗位,有一个结论是反复被验证的:
C 语言不是加分项,而是默认你必须掌握的底层能力。
一开始我对它的理解停留在“会写代码”:
能写循环、判断、函数
会定义结构体
会用指针
能把项目功能跑起来
但只要面试官往下追两层,这套理解就会直接崩掉。真正的分水岭不在“会不会写语法”,而在于你是否把 C 语言当作一门直接和内存、编译器、硬件打交道的底层语言来理解。
下面是我踩坑之后总结出的核心考点和应对方式。
一、C 语言在嵌入式面试中的真实定位
面试官用 C 语言判断的,通常不是“你会不会语法”,而是三件事:
你是否真的理解程序在内存里怎么运行
你是否具备写底层代码的能力
你是否能控制风险,而不是只把代码写“能跑”
如果一个人对 C 语言理解很浅,他写代码通常会有这些特点:
只关注功能是否实现
不关注内存布局和边界
不清楚指针操作的代价和风险
不理解编译器优化可能带来的影响
而嵌入式开发里,很多问题恰恰都出在这些地方:
数组越界
野指针
栈溢出
内存对齐问题
宏替换副作用
中断变量访问异常
volatile 使用错误
函数指针和回调理解不清
所以面试官真正想看的是:你能不能从“写代码”切换到“控制程序行为”的思维。
准备嵌入式面试八股文我推荐这个专栏,真的很全面,很深入:
https://www.nowcoder.com/creation/manager/columnDetail/mPZ4kk
二、最核心的考点:指针不是语法点,而是底层能力分水岭
这一块几乎必问,而且一定会深入。
很多人说自己“会指针”,其实只是会写:
int a = 10; int *p = &a;
但面试官真正关心的是你是否理解:
指针本质上存的是什么
不同类型指针为什么步长不同
一级指针、二级指针分别解决什么问题
数组名和指针到底是什么关系
函数传参时为什么有时能改到外部变量,有时不能
典型追问包括:
int *p[10] 和 int (*p)[10] 的区别
数组指针和指针数组的区别
sizeof(arr) 和 sizeof(p) 为什么不同
函数参数里的数组为什么会退化成指针
为什么 char * 可以做字节级访问
如果你只能停留在“指针就是地址”这句话,基本撑不过连续追问。
真正能拉开差距的回答,必须能把“类型 + 地址 + 偏移 + 内存访问方式”这一整套讲清楚。
三、内存模型一定要清楚:栈、堆、全局区、常量区
这一块在嵌入式面试里杀伤力很强,因为它直接决定你有没有系统观念。
必须清楚:
局部变量通常在栈上
静态变量和全局变量在静态存储区
字符串常量通常在只读区
动态申请的内存在堆上
常见问题:
局部变量函数返回后为什么不能再访问
为什么返回局部数组地址是危险的
全局变量默认初始化在哪里完成
static 修饰局部变量和全局变量分别意味着什么
栈和堆的主要区别是什么
嵌入式里为什么很多场景不推荐频繁 malloc/free
如果你对内存区域的理解是模糊的,后面很多问题都答不深。
因为嵌入式开发本身就是强资源约束场景,面试官默认你必须有“内存敏感性”。
四、结构体、联合体、位域:本质是数据布局能力
这一块特别容易被低估。
很多人觉得结构体就是“把几个变量打包”,但嵌入式里它的核心价值其实是:
定义数据在内存中的组织方式。
你必须掌握:
结构体内存对齐规则
为什么会有 padding
如何减少结构体空间浪费
联合体为什么能共用同一块内存
位域适合什么场景,又有什么风险
高频追问:
下面这个结构体大小是多少
为什么换一下成员顺序,大小会变
联合体适合做什么,不适合做什么
位域能不能完全替代位运算
协议解析和寄存器映射里为什么常用结构体/联合体
如果你答不出“对齐”和“空间布局”,说明你对 C 的理解还停留在源码层,没有落到内存层。
五、宏、const、volatile:这是最容易暴露基础不扎实的地方
这一块不是难,而是太容易被问穿。
必须分清:
#define 是预处理替换,不做类型检查
const 是只读语义约束,不等于一定放在只读存储区
volatile 的核心作用是告诉编译器不要擅自优化对该对象的访问
典型问题:
宏和 inline 函数的区别
带参数宏为什么要加括号
const int *p 和 int * const p 的区别
为什么中断里共享的变量常常要加 volatile
volatile 能不能保证原子性
volatile 和多线程安全是不是一回事
这里最经典的坑就是:
很多人知道“中断变量要加 volatile”,但不知道为什么。
很多人知道“宏有副作用”,但举不出具体例子。
很多人知道“const 很重要”,但说不出它在接口设计中的价值。
如果这些地方讲不清,面试官很容易判断你对 C 语言理解是碎片化的。
六、函数指针和回调机制,是区分“会写业务”和“理解抽象”的关键
很多嵌入式项目里,函数指针不是可选项,而是高频存在:
驱动注册
中断回调
状态机分发
协议处理表
模块接口抽象
你必须掌握:
函数指针的定义方式
函数指针数组的作用
回调函数的典型使用场景
为什么驱动层喜欢用函数指针做解耦
典型问题:
怎么定义一个“参数为 int,返回值为 void”的函数指针
函数指针和普通指针有什么本质区别
回调为什么能降低耦合
状态机为什么常用函数指针表实现
如果这一块只会“背定义”,但说不出工程用途,就很难拿到高评价。
七、C 语言真正高频的面试追问:不是语法,而是边界和风险
很多技术面问 C,不是为了考你标准答案,而是想看你有没有风险意识。
比如这些问题非常高频:
memcpy 和 memmove 的区别
strcpy / strncpy 有什么风险
数组越界为什么危险
空指针和野指针有什么区别
什么是内存泄漏
什么是悬空指针
如何避免重复释放
为什么未初始化指针危险
为什么不能随便强制类型转换
这些题的本质都不是背定义,而是在考:
你写代码时有没有“失控意识”。
嵌入式里一旦失控,后果通常不是“程序报错退出”,而是:
系统偶现异常
死机
数据错乱
中断失效
现场难复现
所以面试官非常看重你是否对这些问题敏感。
八、我后来是怎么把 C 语言这一块补起来的
后期我不再把 C 当成“语法复习”,而是换了三种准备方式。
1. 把所有核心知识都落到“内存视角”去理解
比如指针、数组、结构体、函数参数,我不再只记结论,而是强迫自己回答:
它在内存里长什么样
地址怎么变化
编译器怎么处理
实际访问的到底是哪一块区域
只要你能从内存角度解释问题,很多追问自然就能扛住。
2. 把项目里的 C 代码重新按“语言能力”拆开讲
以前我讲项目,只会说:
做了串口通信
做了 ADC 采集
做了协议解析
后来我会主动补上这些内容:
为什么这个缓冲区要设计成环形队列
为什么这里用结构体封装协议帧
为什么中断和主循环共享变量要加 volatile
为什么这里不用动态内存
为什么回调接口用函数指针
同样是一个项目,面试官对你的判断会完全不一样。
因为你展示出来的,不再只是“做过功能”,而是“理解实现背后的语言机制”。
3. 主动准备 C 语言的追问链条
比如“指针”这个点,我后来会准备整条链:
指针本质是什么
类型为什么重要
指针运算怎么发生
数组和指针什么关系
函数参数为什么退化
二级指针有什么场景
常见风险是什么
再比如“volatile”这个点,我会准备:
它解决什么问题
不加会怎样
适用场景有哪些
它不解决什么问题
为什么它不能代替锁或临界区
你会发现,真正高质量的回答,基本都不是“一个问题一个答案”,而是“一个点能展开成一条逻辑链”。
九、一个很现实的结论
在嵌入式面试里,C 语言出现的频率高得离谱,而且几乎不会只停留在表面。
真正能过的回答,通常具备三个特点:
能从内存和编译角度解释问题
能结合具体项目说明为什么这样写
能扛住连续追问,而不是只会背概念
而不是:
会写基础语法
刷过几道 C 题
看过八股总结
能把 demo 跑起来
如果只剩最后一段时间准备嵌入式面试,我会把 C 语言放在非常高的优先级。
原因很简单:
它不是一门单独的语言题,而是你所有底层能力的共同入口。
你把 C 讲清楚了,指针、内存、编译、驱动、RTOS、协议、系统稳定性,很多问题都能顺着讲下去。
它考的不只是基础,更是你有没有成为一个真正能写底层代码的工程师。

