面灵AI→

嵌入式面试基础 20 题:指针、中断、RTOS 与启动流程

轮次
面试合集
时间
2026-10
来源
牛客网

《面试题目》

  1. 指针和数组有什么区别?
  2. 堆和栈有什么区别?
  3. static 关键字有哪些常见用法?
  4. 为什么需要 volatile?
  5. const 和 volatile 能一起用吗?
  6. 大小端是什么?怎么判断?
  7. 结构体内存对齐是怎么回事?
  8. 中断和轮询怎么选?
  9. 中断服务函数里能做什么,不能做什么?
  10. 关中断、临界区、互斥锁有什么区别?
  11. GPIO 推挽输出和开漏输出有什么区别?
  12. UART、SPI、I2C 怎么对比?
  13. DMA 解决什么问题?有什么风险?
  14. 什么是硬实时和软实时?
  15. 任务调度里,抢占式和协作式有什么区别?
  16. 信号量和互斥锁怎么区分?
  17. 什么是优先级反转?怎么缓解?
  18. 复位后到 main 之前,大概会发生什么?
  19. 野指针、悬空指针、内存泄漏有什么区别?
  20. 看门狗是干什么的?为什么不能乱喂?

《参考解析》

指针和数组的区别,面试官想听的是“类型”和“退化”。 数组是一块连续对象,有确定大小,sizeof(arr) 是总字节数;数组名在多数表达式里退化成指向首元素的指针,但数组本身不是指针变量,不能重新赋值。作为函数参数时,数组形参会退化成指针,长度信息丢失,所以必须额外传长度。堆和栈的区别则要落到生命周期和管理方式:栈由编译器和调用约定自动分配释放,速度快、空间有限,局部大数组和深递归容易溢出;堆用 malloc/free 或 RTOS 的堆管理,灵活但会碎片化,常见问题是泄漏、重复释放和越界。嵌入式里还要区分主栈、任务栈和中断栈。

volatile 只保证“每次都从内存读”,不保证原子和线程安全。 它适合硬件寄存器、中断与主循环共享的标志、以及可能被外部修改的变量;它不会阻止编译器重排所有指令,也不能替代锁或原子操作。const 和 volatile 可以一起用,典型是只读状态寄存器:程序不许写,但硬件会改变它的值。static 修饰局部变量时延长生命周期、只初始化一次;修饰全局变量或函数时限制链接作用域,让符号只在当前编译单元可见。结构体对齐则是编译器按成员对齐要求插 padding,协议解析时没对齐好就会错位,#pragma pack 能改布局但可能牺牲访问效率。

中断和并发的答题要落到“上下文”和“最坏路径”。 ISR 应该短:清标志、搬数据、给信号量/队列、置事件;不要在 ISR 里做长计算、阻塞等待、大量打印或动态申请。printf 可能带锁、走缓冲、触发总线访问,在中断里容易拖长关中断时间甚至死锁。关中断是屏蔽中断,影响面大,只能很短;临界区是保护共享资源的一小段代码,实现可能是关调度、关中断或加锁;互斥锁用于任务间互斥,通常支持优先级继承,不能在 ISR 里随便用。信号量偏“事件计数/资源数量通知”,互斥锁偏“所有权保护”,拿信号量当互斥锁用是经典误用。

优先级反转是实时系统的高频追问。 低优先级任务持有锁,高优先级任务等锁,中优先级任务又抢占了低优先级任务,结果高优先级任务被间接拖慢。缓解手段包括优先级继承(持锁者临时提升到等待者的优先级)、优先级天花板、缩短持锁时间、理顺资源层级。调度方面,抢占式让高优先级任务就绪后立即打断低优先级任务,实时性更好;协作式靠任务主动让出 CPU,实现简单但一个坏任务能卡住系统。硬实时是超时即失败,软实时是超时只降体验,有 RTOS 不等于硬实时,关键看最坏执行时间和阻塞路径。

启动流程和看门狗是“系统观”题。 复位后先取复位向量、设置栈顶、跳到复位处理,初始化 .data(从 Flash 搬到 RAM)、清 .bss、准备 C 运行时,然后才进 main;Bootloader、链接脚本和启动文件的问题都会落在这段。看门狗用于系统失控后强制复位,正常路径要按时喂狗,证明关键任务还活着;在高优先级定时中断里无脑喂狗是典型错误,因为主业务死循环了系统也不会复位。野指针是未初始化或指向非法地址,悬空指针是对象已释放但指针还留着旧地址,内存泄漏是申请后不释放;三者在嵌入式里常表现为跑久了重启、偶发 HardFault 或任务栈耗尽。