嵌入式八股-面试40题(20240814)

1. 关键字 static 的作用是什么?

  • 在函数内static 修饰的变量为静态局部变量,生命周期从程序开始到结束,且在多次函数调用间保持值不变。
  • 在文件内static 修饰的全局变量或函数具有文件内链接,限制其作用域仅限于定义它的源文件,不能被其他文件访问。
  • 在类中static 修饰的成员变量或成员函数属于类而非对象,可以通过类名直接访问。

2. 关键字 const 是什么意思?

  • const 表示常量修饰符,用于声明变量值不能被修改。它可以修饰变量、指针、函数参数以及函数返回值。
    • 修饰变量:变量值不可变。
    • 修饰指针:可以是指针指向的值不可变,或指针自身不可变,或两者都不可变。
    • 修饰函数参数:函数内部不能修改传入的参数值。
    • 修饰函数返回值:防止返回值被修改。

3. const 和宏定义的区别

  • 类型检查const 有类型检查,编译时检测类型错误,而宏定义没有类型,替换时直接进行文本替换。
  • 作用域const 有作用域,遵循变量的作用域规则,宏定义是全局有效的。
  • 调试const 变量在调试时可以看到值,宏替换后看不到值,只能看到替换后的结果。

4. 关键字 volatile 有什么含义并给出三个不同的例子

  • volatile 告诉编译器该变量可能被系统、硬件或者其他线程修改,不要对其进行优化,即每次使用该变量时都从内存中读取值。

    例子

    1. 硬件寄存器volatile int *statusReg = (int *)0x1234;,硬件设备的状态寄存器,可能被外部硬件更改。
    2. 多线程变量volatile bool flag = false;,多线程访问的标志位,可能被其他线程修改。
    3. 中断服务程序中的变量:在中断服务程序中更新的全局变量,需要使用 volatile 修饰,以防止主程序的优化。

5. 引用和指针有什么区别

  • 引用:必须初始化,不能为NULL,创建后不可更改指向,类似别名。
  • 指针:可以为NULL,可以改变指向,可以指向不同的内存地址。

6. .h 头文件中的 #ifndef/#define/#endif 的作用

  • 防止头文件重复包含(头文件保护符),确保头文件内容只被包含一次。

7. 描述实时系统的基本特性

  • 确定性:操作在规定时间内完成。
  • 可靠性:系统在任何时候都能正常工作。
  • 响应性:能够及时响应外部事件。

8. 全局变量和局部变量的区别

  • 作用域:全局变量在整个程序中有效,局部变量只在声明它的块内有效。
  • 生命周期:全局变量在程序运行期间一直存在,局部变量在其作用域结束时销毁。

9. 全局变量和静态全局变量的区别

  • 作用域:静态全局变量的作用域仅限于定义它的文件,普通全局变量可被其他文件访问(通过 extern 声明)。
  • 生命周期:二者在程序生命周期内一直存在。

10. static 函数与普通函数

  • 作用域static 函数的作用域限制在定义它的源文件内,普通函数可以在整个程序中使用。

11. 什么是平衡二叉树?

  • 平衡二叉树(AVL树):任意节点的左右子树高度差不超过1的二叉搜索树。

12. 堆栈溢出一般是由什么原因导致的?

  • 递归调用过深:函数调用自身过多次导致栈空间耗尽。
  • 大数组分配在栈上:数组过大导致栈空间不足。
  • 无限递归:没有正确终止条件的递归调用。

13. 什么函数不能声明为虚函数?

  • 构造函数:不能声明为虚函数,因为在对象创建时,虚函数表还未构建完成。

14. 不能做 switch() 的参数类型

  • switch 语句的参数类型必须是整型(包括 charintenum)。不支持浮点数、字符串或指针类型。

15. 程序的内存分配

  • :用于函数调用时的参数传递和局部变量的存储,自动管理。
  • :动态内存分配,需手动管理(如 mallocfree)。
  • 数据段:存放全局变量和静态变量。
  • 代码段:存放程序的可执行代码。

16. 堆与栈的区别

  • 管理方式:堆是动态分配的,需要程序员手动管理;栈由编译器自动分配和释放。
  • 空间大小:堆的大小由系统决定且通常较大,栈的大小受限。
  • 碎片问题:堆存在内存碎片问题,栈不存在。

17. 描述内存分配方式以及它们的区别

  • 静态内存分配:在编译时分配,大小固定,例子:全局变量、静态变量。
  • 动态内存分配:在运行时分配,大小可变,例子:mallocnew

18. mallocnew 的区别是什么?

  • 初始化malloc 只分配内存,不调用构造函数;new 除分配内存外,还调用构造函数初始化对象。
  • 返回类型malloc 返回 void*,需强制类型转换;new 返回具体类型的指针。

19. 进程与线程的区别

  • 内存空间:进程拥有独立的内存空间,线程共享进程的内存空间。
  • 通信:进程间通信(IPC)复杂,线程间通信相对简单。
  • 资源消耗:创建和切换进程的开销比线程大。

20. 多进程和多线程的区别

  • 多进程:程序的多个独立执行单元,独立的内存空间,适合CPU密集型任务。
  • 多线程:进程内部的多个执行单元,共享内存空间,适合IO密集型任务。

21. 什么是预编译,何时需要预编译

  • 预编译:编译前对代码进行处理,如宏替换、头文件展开等,通常用于加快编译速度或处理跨平台代码。

22. 三种基本的数据模型

  • ILP32intlongpointer 都是 32 位。
  • LP64longpointer 是 64 位,int 是 32 位。
  • LLP64long longpointer 是 64 位,int 是 32 位。

23. 简述数组与指针的区别?

  • 数组:存储一组连续的相同类型的元素,大小固定。
  • 指针:存储内存地址,可以指向数组的元素或其他变量。

24. 位操作

  • 常见操作:与(&)、或(|)、异或(^)、取反(~)、左移(<<)、右移(>>)。
  • 用途:用于硬件操作、权限管理、状态标志等。

25. 访问固定的内存位置(Accessing fixed memory locations)

  • 通过指针访问固定的内存地址,比如硬件寄存器:
    int *reg = (int *)0x12345678;
    *reg = 0xFF;
    

26. 中断与异常的区别

  • 中断:由外部事件触发,通常由硬件发起。
  • 异常:由CPU执行指令时内部事件触发,如除零错误。

27. 变量的定义总结

  • 自动变量:局部变量,生命周期在作用域内,存储在栈中。
  • 静态变量:生命周期为整个程序运行期间,存储在数据段。
  • 寄存器变量:尽

量存储在CPU寄存器中,生命周期在作用域内。

  • 全局变量:生命周期为整个程序运行期间,作用域为整个程序。

28. 为什么要使用宏,宏有什么优缺点?

  • 优点:提高代码可读性和复用性,条件编译,代码简洁。
  • 缺点:无类型检查,调试困难,滥用可能导致代码难以维护。

29. 内联函数及与宏的区别

  • 内联函数:通过 inline 关键字修饰,函数调用时展开,支持类型检查,调试友好。
  • :直接文本替换,无类型检查,容易出错。

30. MCU 启动过程

  • 典型过程
    1. 电源上电或复位信号触发。
    2. 程序计数器跳转到复位向量。
    3. 初始化堆栈指针。
    4. 执行初始化代码(如数据段初始化)。
    5. 跳转到 main 函数。

31. ARM 体系结构

  • ARM 架构:精简指令集计算(RISC)架构,具有高效能耗比。
  • 特点:Thumb 指令集、低功耗、广泛用于嵌入式设备。

32. 什么是嵌入式?

  • 嵌入式系统是一个专用计算机系统,通常集成于控制设备中,具有特定的功能。

33. 进程与线程中的通信方式

  • 进程通信:管道、消息队列、共享内存、信号量。
  • 线程通信:共享内存、条件变量、信号量、互斥锁。

34. 如何将 PC 上的程序移植到嵌入式系统上,需要注意些什么?

  • 硬件差异:不同处理器架构、存储限制。
  • 实时性:嵌入式系统对实时性有更高要求。
  • 资源管理:嵌入式系统资源有限,需要优化内存和功耗。

35. 设计一种通信方式,从一台主机向另外一台主机传递数据,那么应该怎么选择。

  • 选择合适的通信协议和方式:如以太网、UART、SPI、I2C,基于通信距离、带宽需求、实时性等因素。

36. FreeRTOS 之全配置项详解、裁剪(FreeRTOSConfig.h)

  • 配置项:如任务优先级、内存管理、调度策略、钩子函数等,裁剪是根据需求去除不必要的功能以减少资源占用。

37. DMA 为什么能提高效率?

  • DMA(直接内存访问)能够在不占用CPU的情况下,直接在内存与外设之间传输数据,提高了系统的整体效率。

38. 优先级反转以及解决方法

  • 优先级反转:低优先级任务持有资源时,高优先级任务被阻塞,中优先级任务占用CPU,导致高优先级任务无法执行。
  • 解决方法:使用优先级继承机制,提升持有资源的低优先级任务的优先级。

39. 信号量及信号量与自旋锁的区别

  • 信号量:用于线程间同步或资源计数,支持线程休眠等待。
  • 自旋锁:用于短时间锁定资源,忙等待,不释放CPU。

40. strcpystrncpy 的缺陷

  • strcpy:不检查目标缓冲区大小,可能导致缓冲区溢出。
  • strncpy:如果源字符串长度超过目标缓冲区,目标字符串可能不以 \0 结尾,需要手动添加 \0
嵌入式开发面试通常包括以下几个方面的内容: 1. 嵌入式系统基础知识:包括什么是嵌入式系统、嵌入式系统的特点、嵌入式系统的应用等。 2. C/C++编程语言:包括基本语法、数据类型、指针、内存管理、函数、结构体、文件操作等。 3. 操作系统:包括实时操作系统(RTOS)的原理、任务调度、进程间通信、内存管理等。 4. 单片机/微处理器:包括常见单片机/微处理器的特点、寄存器、外设接口、中断处理等。 5. 通信协议:包括串口通信、SPI、I2C、CAN总线等常用的通信协议。 6. 电路设计:包括数字电路设计、模拟电路设计、常用传感器的接口等。 7. 嵌入式系统调试与测试:包括调试工具的使用、代码调试技巧、性能优化等。 8. 项目经验:展示自己在嵌入式开发领域的项目经验,包括项目的整体架构、关键技术、遇到的问以及解决方案等。 9. 算法与数据结构:包括常见的排序算法、查找算法、链表、树等。 根据你提供的引用内容,可能在面试中会问到关于进程和线程的问。进程是计算机中正在运行的程序的实例,而线程是进程中的一条执行路径。在嵌入式开发中,进程与线程的概念同样适用。你可能会被问到进程和线程的区别、进程间通信的方式、线程同步与互斥等问。 记住,除了准备好上述的知识点和问,还可以通过阅读相关的书籍和参加一些实际的嵌入式开发项目来提高自己的面试准备。祝你成功!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sagima_sdu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值