【嵌入式软件】面试笔试问题整理 (持续更新)

题目答案分离,方便自查自测

快速跳转:

面试笔试问题

1. 关键字static有什么用途?(请至少说明两种)

答:
在 C 语言中,static 是一种类型声明符,主要有三个用途:声明静态局部变量、声明静态外部全局变量和声明静态外部函数。下面是对这三个用途的详细解释。

(1)声明静态局部变量

静态局部变量是使用 static 声明的局部变量,其存储空间分配在静态存储区,作用域仅仅限于声明该变量的函数内部。在程序整个运行期间都不释放,生存期贯穿于程序运行的整个过程。与 auto 类型变量相比,static 变量的存储空间分配在静态存储区,而 auto 变量的存储空间分配在栈上。

在赋初值时,static 变量是在编译时赋初值,即只赋初值一次;而 auto 变量赋初值是在函数调用时进行,每调用一次函数重新给一次初值,相当于执行一次赋值语句。如果在定义局部变量时不赋初值的话,static 变量将自动赋初值 0(对数值型变量)或空字符(对字符变量),而 auto 变量的值是一个不确定的值。

(2)声明静态外部全局变量

在 C 语言中,static 还用来声明静态外部全局变量,那么这个全局变量的作用域就被限制在本文件内部。外部变量(即全局变量)是在函数的外部定义的,它的作用域为从变量定义处开始,到本程序文件的末尾。如果外部变量不在文件的开头定义,其有效的作用范围只限于定义处到文件终了。如果在定义点之前的函数想引用该外部变量,则应该在引用之前用关键字 extern 对该变量作“外部变量声明”。表示该变量是一个已经定义的外部变量。如果我们声明的全局变量不想被其他文件访问和使用,那就是在声明的时候前面加上关键字 static。

(3)声明静态外部函数

在 C 语言中,我们的函数默认都是全局的,也就是说你可以调用其他文件中的函数。在使用的时候,我们象前面一样在头文件中加上 extern 就可以了。但是有时候我们写的函数并不想让别的文件访问和调用,那么我们在声明函数的时候前面加上 static 就可以了。使用内部函数的好处有二:一是可以让某些内部函数不为人所能使用,而仅仅让调用者使用他能使用的东西,有利于保护代码;二是不用担心自己定义的函数是否会与其它文件中的函数同名。

2. 嵌入式系统中经常要用到无限循环,如何用C编写死循环?

答:while(1){}或者for( ; ; )。

3. 程序的局部变量存在于哪里,全局变量存在于哪里,动态申请数据存在于哪里?

答:程序的局部变量存在于栈区;全局变量存在于静态区;动态申请数据存在于堆区。

4. 什么是平衡二叉树?

答:左右子树都是平衡二叉树 且左右子树的深度差值的绝对值不大于1

5. 解释一下进程、线程、协程的概念。

答:
进程:是并发执行的程序在执行过程中分配和管理资源的基本单位,是一个动态概念,竞争计算机系统资源的基本单位。
线程:是进程的一个执行单元,是进程内科调度实体。比进程更小的独立运行的基本单位。线程也被称为轻量级进程。
协程:是一种比线程更加轻量级的存在。一个线程也可以拥有多个协程。其执行过程更类似于子例程,或者说不带返回值的函数调用。

6. 解释一下进程和线程的区别。

答:
(1)地址空间:线程共享本进程的地址空间,而进程之间是独立的地址空间。
(2)资源:线程共享本进程的资源如内存、I/O、cpu等,不利于资源的管理和保护,而进程之间的资源是独立的,能很好的进行资源管理和保护。
(3)健壮性:多进程要比多线程健壮,一个进程崩溃后,在保护模式下不会对其他进程产生影响,但是一个线程崩溃整个进程都死掉。
(4)执行过程:每个独立的进程有一个程序运行的入口、顺序执行序列和程序入口,执行开销大。但是线程不能独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制,执行开销小。
(5)可并发性:两者均可并发执行。
(6)切换时:进程切换时,消耗的资源大,效率高。所以涉及到频繁的切换时,使用线程要好于进程。同样如果要求同时进行并且又要共享某些变量的并发操作,只能用线程不能用进程。
(7)其他:线程是处理器调度的基本单位,但是进程不是。

7. 解释一下协程和线程的区别。

答:
协程避免了无意义的调度,由此可以提高性能,但程序员必须自己承担调度的责任。同时,协程也失去了标准线程使用多CPU的能力。
线程相对独立有自己的上下文切换受系统控制;协程相对独立有自己的上下文切换由自己控制,由当前协程切换到其他协程由当前协程来控制。

8. 何时使用多进程,何时使用多线程?

对资源的管理和保护要求高,不限制开销和效率时,使用多进程。要求效率高,频繁切换时,资源的保护管理要求不是很高时,使用多线程。

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

答:
没有回收垃圾资源

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

答:
构造函数,因为它是在对象产生之头被调用的,而虚函数是对象产生之后才起作用的机制,所以声明虚构造函数无意义。

11. Internet采用哪种网络协议?该协议的主要层次结构?

答:
tcp/ip 应用层/传输层/网络层/链路层。

12. 局部变量能否和全局变量重名?

答:
能,局部会屏蔽全局。要用全局变量,需要使用"::"
局部变量可以与全局变量同名,在函数内引用这个变量时,会用到同名的局部变量,而不会用到全局变量。对于有些编译器而言,在同一个函数内可以定义多个同名的局部变量,比如在两个循环体内都定义一个同名的局部变量,而那个局部变量的作用域就在那个循环体内。

13. 如何引用一个已经定义过的全局变量?

答:
extern关键字
可以用引用头文件的方式,也可以用extern关键字,如果用引用头文件方式来引用某个在头文件中声明的全局变理,假定你将那个变写错了,那么在编译期间会报错,如果你用extern方式引用时,假定你犯了同样的错误,那么在编译期间不会报错,而在连接期间报错。

14. 关键字volatile有什么含意?并给出三个不同的例子。

答:
一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。下面是volatile变量的几个例子:

  1. 并行设备的硬件寄存器(如:状态寄存器)。
  2. 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)。
  3. 多线程应用中被几个任务共享的变量。

15. STM32的主要组成部分是什么?

答:
STM32微控制器的主要组成部分围绕着其核心——ARM Cortex-M系列处理器,并包括一系列的片上外设、存储器、总线架构以及其他辅助电路。以下是STM32的一些关键组成部分:

  1. ARM Cortex-M内核

    • STM32使用ARM Cortex-M系列内核,如Cortex-M0、M0+、M3、M4、M7等,这些内核提供了高性能和低功耗的平衡。
  2. 存储器

    • Flash Memory:用于存放程序代码和常量数据。
    • SRAM:作为工作内存,用于存放变量和运行时数据。
    • STM32还可能包含EEPROM或内置的非易失性存储器。
  3. 总线架构

    • AHB(Advanced High-performance Bus):高速总线,连接到CPU、DMA、总线矩阵和一些高速外设。
    • APB(Advanced Peripheral Bus):较低速的总线,用于连接低速外设和一些时钟频率较低的外设。
    • System Bus:用于连接CPU和各种内部组件。
    • ICode/DCode Buses:用于指令和数据的分离传输。
  4. 外设

    • GPIO(General-Purpose Input/Output):通用输入输出端口。
    • 定时器:用于产生精确的延时和计数。
    • ADC(Analog-to-Digital Converter):用于将模拟信号转换为数字信号。
    • DAC(Digital-to-Analog Converter):用于将数字信号转换为模拟信号。
    • USART/SPI/I²C:用于串行通信。
    • DMA(Direct Memory Access):用于在没有CPU干预的情况下在内存和外设之间传输数据。
    • CAN(Controller Area Network):用于汽车和工业自动化网络通信。
    • USB(Universal Serial Bus):用于高速数据传输和设备连接。
    • Ethernet:用于网络通信。
    • CRC(Cyclic Redundancy Check):用于数据完整性校验。
  5. 电源管理与时钟控制

    • 电源管理单元:用于控制不同电压域的电源供给。
    • 时钟管理器:用于生成和控制各种时钟信号,如HSI(内部高速)、HSE(外部高速)、LSI(内部低速)、LSE(外部低速)等。
  6. 安全和加密

    • 加密引擎:用于数据加密和解密。
    • 真随机数生成器(TRNG):用于生成随机数。
  7. 调试和跟踪

    • JTAG/SWD(Serial Wire Debug):用于调试和编程。
    • ETM(Embedded Trace Macrocell):用于跟踪CPU的执行路径。
  8. 高级特性

    • 在某些STM32系列中,可能还会包括FPU(浮点运算单元)、DSP(数字信号处理器)指令集、MPU(Memory Protection Unit)等高级特性。

这些组成部分共同构成了STM32微控制器的强大功能和灵活性,使其适合广泛的应用领域,从简单的数据采集和控制,到复杂的通信和多媒体处理。

16. 描述STM32中的中断向量表和中断处理过程。

答:

STM32的中断向量表位于内存的最开始处,即0x08000000地址开始的位置。这个位置通常是闪存的起始地址,但由于STM32的启动配置,中断向量表通常被映射到SRAM区域,以加快中断响应速度。

中断向量表包含了所有的中断向量,每个向量占用4个字节,指向中断服务子程序的起始地址。除了中断向量之外,STM32的IVT还包括复位向量、未定义指令异常、软件中断、预取异常等异常处理向量。

中断处理过程通常遵循以下步骤:
(1)中断请求:当一个外部事件触发中断请求时,相应的中断线被激活。
中断挂起和优先级检查:中断挂起机制确保高优先级的中断可以打断低优先级的中断。中断优先级由NVIC(Nested Vectored Interrupt Controller)管理,它可以配置中断的抢占优先级和响应优先级。
(2)中断向量查找:一旦确定中断要被处理,STM32会查找中断向量表中对应的中断向量地址。
(3)保存上下文:在跳转到中断服务程序之前,STM32会自动保存当前处理器的状态,包括PC(程序计数器)、LR(链接寄存器)和其他寄存器的内容。
(4)执行中断服务程序:处理器跳转到中断向量指向的地址,开始执行中断服务程序。中断服务程序负责处理中断事件,比如读取传感器数据、更新状态机、驱动硬件等。
(5)恢复上下文:在中断服务程序执行完毕后,处理器恢复被保存的上下文,返回到中断前的指令继续执行。
(6)清除中断标志:通常,中断服务程序会清除相应的中断标志位,表示该中断已经被处理。

17. C语言中头文件中的 ifndef/define/endif 干什么用?

答:
在C语言中,#ifndef, #define, 和 #endif 是预处理指令,它们通常一起使用来防止头文件的内容被多次包含。这种技术被称为“包含保护”或“头文件保护”。

当一个头文件被多次包含时,如果没有适当的保护,可能会导致以下问题:
符号重复定义:如果头文件中有定义,比如全局变量或函数体的定义,多次包含会导致链接错误。
符号重复声明:虽然多次声明相同类型的变量或函数不会直接导致编译错误(如果遵循C99标准),但它会使得代码冗余且不易维护。

18. 解释一下TCP、UDP的区别。

答:
TCP(传输控制协议)和UDP(用户数据报协议)是两种常见的网络传输协议,它们有以下区别:

(1)连接:TCP是面向连接的协议,而UDP是无连接的协议。在发送数据前,TCP通过三次握手建立连接,而UDP不需要建立连接。
(2)可靠性:TCP提供可靠的数据传输,保证了数据的可靠性和完整性。TCP通过序号、确认应答和超时重传等机制来实现可靠性。而UDP不提供可靠性保证,数据可能丢失、损坏或重复。
(3)传输速度:UDP比TCP快,因为它不需要建立连接和提供可靠性保障。在一些场景中,如视频、音频等实时应用,UDP更适合。
(4)数据量限制:UDP的数据包大小通常受限于底层网络协议(如以太网),一般不超过1472字节。而TCP的数据包大小则取决于操作系统和底层网络协议。
(5)应用场景:TCP适用于可靠性要求高的应用场景,如网页浏览、电子邮件等。UDP适用于对速度和实时性要求高的应用场景,如在线游戏、视频流等。
(5)头部开销:TCP的首部较大,为20个字节,而UDP的首部较小,为4个字节。
总的来说,TCP提供了可靠的连接和数据传输,但相对较慢;而UDP快,但数据传输不可靠。在选择传输协议时,需要根据具体的应用场景来权衡。

19. STM32的时钟系是如何工作的?

答:
STM32的时钟系统相当复杂,它由多个时钟源和时钟树组成,旨在提供高度灵活和可配置的时钟管理。下面是一个概括性的描述,解释STM32时钟系统的基本工作原理:

  1. 时钟源:

    • HSI (High Speed Internal Oscillator): 内部高速RC振荡器,典型频率为16 MHz。
    • HSE (High Speed External Oscillator): 外部高速晶体振荡器,频率范围通常在4 MHz到26 MHz。
    • LSI (Low Speed Internal Oscillator): 内部低速RC振荡器,频率大约为32 kHz。
    • LSE (Low Speed External Oscillator): 外部低速晶体振荡器,通常为32.768 kHz。
  2. PLL (Phase Locked Loop):

    • PLL可以使用HSI、HSE或外部时钟信号作为输入,通过倍频或分频产生更高的时钟频率,用于系统时钟(SYSCLK)。
  3. 系统时钟 (SYSCLK):

    • 系统时钟可以是HSI、HSE、PLL的输出,或者是LSI经过预分频器(PLL)之后的输出。
    • SYSCLK频率决定了STM32的核心运行速度,以及所有依赖于系统时钟的外设的频率。
  4. APB (Advanced Peripheral Bus):

    • APB1和APB2总线分别连接低速和高速外设,它们的频率由SYSCLK通过预分频器决定。
    • APB1的频率通常低于APB2的频率。
  5. AHB (Advanced High-performance Bus):

    • AHB总线连接高速外设和内存,其频率等于SYSCLK。
  6. RTC (Real-Time Clock):

    • RTC有自己的独立时钟源,通常使用LSE或LSI,即使在其他时钟关闭时也能保持运行。
  7. 控制和配置:

    • 时钟的配置和控制主要通过RCC(Reset and Clock Control)寄存器完成,包括时钟的启用和禁用、分频和倍频、选择时钟源等。
  8. 时钟树:

    • 时钟树是一种图形化表示,展示了时钟信号如何从各个时钟源开始,通过分频、倍频和选择,最终分配给不同的总线和外设的过程。

在使用STM32时,开发者通常需要根据应用需求选择合适的时钟源和配置,以达到最佳的性能和功耗平衡。例如,在需要高速运行的应用中,可能会选择HSE作为PLL的输入,然后将PLL的输出作为系统时钟;而在低功耗应用中,则可能选择HSI或LSI作为系统时钟源。

20. 什么是死锁?产生死锁的原因是什么?

死锁(Deadlock)是指两个或更多的进程或线程永久地阻塞,每个进程或线程都在等待另一个进程或线程释放资源,从而形成一个循环依赖,没有任何进程能够继续执行的情况。死锁是一种僵局状态,除非有外部干预,否则参与死锁的进程将无法继续执行或终止。

产生死锁的本质原因为:

(1)系统资源有限。

(2)进程推进顺序不合理。

21. 全局变量可不可以定义在可被多个.C文件包含的头文件中?为什么?

答:
可以,在不同的C文件中以static形式来声明同名全局变量。
可以在不同的C文件中声明同名的全局变量,前提是其中只能有一个C文件中对此变量赋初值,此时连接不会出错

22. Heap与stack的差别。

答:
Heap是堆,stack是栈。
Stack的空间由操作系统自动分配/释放,Heap上的空间手动分配/释放。
Stack空间有限,Heap是很大的自由存储区

23. 使用malloc之前需要做什么准备工作。

答:
在使用 malloc 函数之前,你需要确保:
已经包含了 <stdlib.h> 头文件,因为 malloc 函数定义在此头文件中。
清楚你需要分配多少字节的内存。malloc 的参数是所需内存大小的字节数。
准备一个指针变量来存储 malloc 返回的地址。通常会进行类型转换,例如 (int*) malloc(sizeof(int) * 10);

24. realloc函数在使用上要注意什么问题。

答:
realloc 函数用于改变已分配内存块的大小。使用时应注意以下几点:
(1)与 malloc 类似,确保包含了 <stdlib.h>。
(2)realloc 的第一个参数是一个指向已分配内存的指针,第二个参数是要调整到的新大小。
(3)如果 realloc 成功,它会返回一个新的指针(可能是原来的,也可能是新位置的),所以你必须更新你的指针变量。
(4)如果 realloc 失败,它可能返回 NULL,并且不释放原来的内存,所以你应该检查返回值并做适当的错误处理。
(5)调整大小可能会导致数据丢失或未初始化的数据,如果新大小小于原大小,超出的部分会被截断;如果新大小大于原大小,新增的部分未初始化。

25. strtok函数在使用上要注意什么问题。

答:
strtok 是用于字符串分割的函数,使用时需注意:
(1)包含 <string.h> 头文件。
(2)第一次调用 strtok 时,需要提供要分割的字符串和分隔符作为参数。
(3)在后续调用 strtok 时,只需提供分隔符,因为 strtok 会记住上次操作的位置。
(4)strtok 会修改原始字符串,在每个分隔符处插入空字符 \0。
(5)如果字符串中有连续的分隔符,strtok 会返回空字符串。
(6)strtok 可能返回 NULL,表示没有更多的子串可以分割。

26. gets函数在使用上要注意什么问题。

答:
在C语言中,gets() 函数被设计用来从标准输入读取一行文本,并且不考虑换行符,直接将其作为一个终止符。然而,由于其设计上的缺陷,gets() 函数存在严重的安全风险,主要在于它不能防止缓冲区溢出。这意味着如果用户输入的文本长度超过了目标缓冲区的大小,gets() 将继续写入数据,覆盖缓冲区后的内存,这可能导致程序崩溃或者被恶意利用。

27. ADC的工作模式共有几种?分别是什么?

答:
共有四种:单次 ;连续;扫描;不连续采样

28. DMA的工作方式共有几种,它的作用是什么?

答:
DMA的工作方式共有两种:正常和循环模式

DMA的作用是用于在外设与存储器之间以及存储器与存储器之间提供高速数据传输可以在无需任何CPU操作的情况下通过DMA快速移动数据这样节省的CPU资源可供其它操作使用。

29. DMA和中断的区别是什么?

答:

①DMA是硬件方式,中断是软件方式

②DMA不需要CPU参与,中断是需要CPU参与

③DMA只能搬运数据,中断可以处理一些其他事情

④DMA的优先级是要高于中断的,中断的优先级是要高于main的

30. 在STM32上实现UART通信的基本步骤是什么?

答:

基本步骤:

  1. 配置GPIO端口
    UART通信需要至少两个引脚:TX(发送)和RX(接收)。首先,需要在GPIO配置中将这些引脚设置为相应的UART功能。
  2. 初始化USART模块
  3. 使能USART中断
  4. 配置DMA(可选)
    如果需要高速数据传输或减轻CPU负担,可以配置DMA来实现异步数据传输。
  5. 发送和接收数据
    发送数据:可以使用 HAL_UART_Transmit() 或者 HAL_UART_Transmit_DMA() 函数。
    接收数据:可以使用 HAL_UART_Receive() 或者 HAL_UART_Receive_DMA() 函数。
  6. 错误处理和中断服务例程
    确保编写适当的错误处理函数和中断服务例程来处理可能发生的错误和中断事件。

🚀 获取工程代码及更多详细资料可点击链接进群领取,谢谢支持!👇

点击免费领取更多资料

  • 14
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值