引导者之歌------------嵌入式软件面试问题集成
目录一、C/C++、Python
sizeof,数据类型地址大小问题
运算符优先级
sizeof()和strlen()
指针常量,常量指针
指针函数,函数指针
指针数组,数组指针
代码问题
步伐/进程的内存分为几个段?
C语言中内存分配有多少种?
栈和堆有什么区别?
const关键字
extern关键字
extern C 的作用是什么编辑
volatile关键字
为什么static只需要初始化一次(static关键字)
new/delete、malloc/free 区别
左值和右值区别,应用?
结构体内存对齐问题
struct 和 union 区别?
大小端存储方式
深拷贝和浅拷贝
内联函数 inline
memcpy和strcpy函数
编译型语言与解释型语言不同
calloc、malloc、realloc函数的区别及用法
二、数据结构与算法
顺序结构(数组)和链式结构(链表)有什么不同,应用在哪些场景?
队列和栈有什么不同,应用场景有哪些?
三、stm32
一个开关控制一个LED灯开关,由stm32做主控,按下按键,灯会时亮时不亮,缘故起因由那些?
RAM
GPIO工作模式
UART和USART区别
中断和DMA不同
IIC读写时序
SPI
FreeRtos调度算法
FreeRtos使命的状态
FreeRtos使命同步方式
环形缓冲区(KFIFO)
FIFO
四、操作体系Linux
基本指令
FreeRtos和Linux的不同
Windows和Linux的多进程有什么不同
动态库和静态库区分与应用
编译过程(编译原理)
进程和线程区别(本质区别:是否共享内存)
多进程和多线程优缺点、应用场景
进程之间通讯有哪些,哪些是需要内核的?
僵尸进程、孤儿进程、保卫进程
线程池
线程安全
原子操作
读写锁和互斥锁
自旋锁
线程通讯队列
OSI七层网络模子
TCP/IP四层协议
TCP和UDP
为什么TCP是三次握手
TCP粘包问题和办理
DHCP协议
MQTT协议(物联网)
一、C/C++、Python
sizeof,数据类型地址大小问题
基本变量:https://i-blog.csdnimg.cn/direct/8a788d0094a8425db02c2dfeced2af01.png
指针:
指针大小在32位操作体系是4字节大小,在 64 位体系中为 8 字节大小。
https://i-blog.csdnimg.cn/direct/0ee7c3b037ec4be5a5009338cdf1e18a.png
答案分别是:16、4、4
a是一个数组,所以大小是4*4=16字节
*a是指向数组a的首位,大小是4字节
&a是表现取地址,指针大小是4字节(在32位操作体系中)
运算符优先级
https://i-blog.csdnimg.cn/direct/83b17f6605d64e9fa58b4c23cc27b820.png
int a = 5;
a += a *= a %= 3;
// a= a%3 a*=a=4a=a+a=8
cout << "a的结果:" << a << endl; // 8 int main(int argc, char const* argv[])
{
int a = 1;
int b = a++ + a++ + ++a;
// 1+2+4=7
printf("%d %d\n", a, b);
// 输出结果:4 7
} sizeof()和strlen()
1.sizeof()是一个运算符;strlen()是一个函数,需要包罗头文件。
2.sizeof()计算的是占用内存的大小;strlen()是表现计算字符串的长度。
#include<stdio.h>
#include<string.h>
int main(int argc, char const* argv[])
{
printf("%d %d\n", sizeof("\0"), strlen("\0"));
} 这个答案是多少? 应该是 2 ,0
字符串是以 \0 作为结尾,所以strlen不管帐算到这个的长度的,答案为0;sizeof计算的是字符串占用内存的大小,其中\0是表现一个字符串,但是C语言字符串末了面会有一个\0作为终止符,所以实际上计算的是\0\0,也就是两个字符的大小,答案是2。
指针常量,常量指针
指针常量如下,这个p是一个常量类型的指针,不能修改这个指针指向的地址,但是这个地址的值是可以修改的。
int * const p; 常量指针如下,这个指针指向常量类型的一个指针,也就是说这个地址里面的东西不能改,但 p 本身可以指向别的地址。
const int *p;
int const *p; https://i-blog.csdnimg.cn/direct/a7807a150629496da361534f814b013d.png
很显然,第一个指向的地址里面的值是不能修改的;第二个是表现这个指针指向的地址是不能修改的。
指针函数,函数指针
2.指针函数
int* arry() {
int* s = new int;
return s;
}
1.函数指针
假如在步伐中界说了一个函数,那么在编译时体系就会为这个函数代码分配一段存储空间,这段存储空间的首地址称为这个函数的地址。而且函数名表现的就是这个地址。既然是地址我们就可以界说一个指针变量来存放,这个指针变量就叫作函数指针变量,简称函数指针。
int add(int a, int b) {
return a + b;
}
int main(int argc, char const* argv[])
{
// 定义函数指针
int (*ptr)(int, int) = &add;
return 0;
}
指针数组,数组指针
int* p; // 指针数组,里面每一个元素都是指针类型
int(*p); // 数组指针,本质是一个指针
int main(int argc, char const* argv[])
{
int a = { 1,2,3,4,5,6 };
int (*p) = a;
cout << **p << endl;
cout << *p << endl;
cout << (*p) << endl;
cout << (*p + 1) << endl;
cout << (*(p + 1)) << endl;
cout << *(*p + 4) << endl;
cout << *((*p + 1) + 0) << endl;
/*
1
4
2
4
4
5
2
*/
}
代码问题
https://i-blog.csdnimg.cn/direct/652cc97265a949a3b636acc110404839.png
这个是不能比力字符串是否相当的,你比如说abc和abcd捏?真正去比力字符串是否雷同的可以去使用KMP算法或者BF算法。
步伐/进程的内存分为几个段?
[*]代码段:用于存储步伐的可执行指令,一般是只读,防止被修改
[*]数据段(Dat):用于存储已经初始化的全局变量和静态变量
[*]BSS段:存储没有初始化的全局变量和静态变量
[*]堆:用malloc和free去手动分配和释放的
[*]栈:用于存储局部变量,栈的内存申请是由操作体系决定的
C语言中内存分配有多少种?
1.栈上分配
2.堆上分配
3.静态存储区分配,比如全局变量、静态变量static
栈和堆有什么区别?
1.栈是由操作体系去主动分配/释放的,堆是由用户去手动分配/释放的。
2.栈的空间分配速率快,堆的分配速率是比力慢的,而且容易出现内存碎片,欠好管理。
3.栈空间是有限的照旧连续的(数组),堆空间黑白常大的而且不是连续的(链表)。
const关键字
[*]修饰界说的变量,设置为常量了
[*]修饰函数的参数,这个函数体内你不能修改这个参数的值
[*]修饰返回值,被修饰的返回值指针,这个指针的执行内容就不能改
extern关键字
【014 关键字】一文彻底搞懂extern用法-CSDN博客
用于声明变量或函数是在其他地方界说的,重要用来办理跨文件访问的问题。
声明可以多次,界说只能一次。
extern C 的作用是什么https://i-blog.csdnimg.cn/direct/0bd361d277f645e5bea6bfd530d5f27e.png
volatile关键字
volatile 是 C/C++ 中的一个关键字,意思是:这个变量可能随时发生变革,不要做优化,要每次都从内存中读取它的值。
#include <iostream>
void delay() {
for (int i = 0;i < 99999;i++) {
for (int j = 0;j < 99999;j++) {
}
}
}
int main(int argc, char const* argv[])
{
std::cout << "1111111" << std::endl;
delay();
std::cout << "222222" << std::endl;
return 0;
}
假如使用 g++ main.cc -o main -O3 去进行编译的话,就会对代码进行优化,所以检测到上面这个delay是属于无效的循环的话,编译器会直接忽略掉的。输出结果直接就是111111 222222,中心没有延时。
https://i-blog.csdnimg.cn/direct/139db5c6d6ad4eff82fa17e9d8bda277.png
https://i-blog.csdnimg.cn/direct/b65d151bf81d43b4a8732040c34dac23.png
void delay() {
for (volatile int i = 0;i < 99999;i++) {
for (volatile int j = 0;j < 99999;j++) {
}
}
} 但是假如加上volatile去声明变量就不同了,这个加上就是告诉编译器这个变量是不稳固的,每次读取的时间只能从内存上去读取,而不是从寄存器或者缓存区读。
所以这里即使开启了编译等级优化,两个输出之间是有耽误的。
为什么static只需要初始化一次(static关键字)
https://i-blog.csdnimg.cn/direct/264cf4c23f3440efb78e0aa3dd7c71c2.png
new/delete、malloc/free 区别
https://i-blog.csdnimg.cn/direct/c6f71c329d3b456eab135e48d8739700.png
左值和右值区别,应用?
[*]左值是指可以出如今等号左边的变量或表达式,它最重要的特点就是可写(可寻址)。也就是说,它的值可以被修改,假如一个变量或表达式的值不能被修改,那么它就不能作为左值。
[*]右值是指只可以出如今等号右边的变量或表达式。它最重要的特点是可读。一般的使用场景都是把一个右值赋值给一个左值。
通常,左值可以作为右值,但是右值不肯定是左值。左值是可以赋值的,右值是不可以赋值的
结构体内存对齐问题
Linux-----结构体与联合体,大小端模式_联合体大小端-CSDN博客
struct 和 union 区别?
1.结构体占用内存大小是等于所有成员大小之和(遵循结构体成员内存对齐);联合体内存是共享的,由成员中占用内存最大的成员决定的。
理论上联合体占用内存大小是根据成员中占用内存最大的成员决定的, 但是实际上一般输出union 的大小 = 最大成员大小(含对齐)。
大小端存储方式
Linux-----结构体与联合体,大小端模式_联合体大小端-CSDN博客
深拷贝和浅拷贝
浅拷贝
[*]是只复制这个指针,多个变量对象使用同一个动态分配的内存
[*]适用于简单类型或者是无需独立管理资源的对象
[*]可能导致内存泄漏或者是多次释放的问题
深拷贝
[*]申请独立的内存空间完全复制前一个对象的全部内容
[*]使用与动态分配内存的对象
[*]每个对象拥有独立的内存空间副本,不会相互影响
内联函数 inline
内联函数是一种特殊的函数声明方式,在函数的前面加上inline关键字。调用的时间是进行展开,而不是直接去调用。这种适用于体量小、功能简单的函数
inline int add(int a, int b) {
return a + b;
}
int main(int argc, char const* argv[])
{
int result = add(7, 8);
printf("%d\n", result);
} 优点
[*]减小函数调用的开销
[*]进步执行服从
[*]答应编译器进行优化,减少冗余,进步性能
memcpy和strcpy函数
[*]void* memcpy( void* dest, const void* src, std::size_t count );
[*]char* strcpy( char* dest, const char* src );
[*]memcpy是属于内存拷贝,不受数据类型限定按照字节数去拷贝,适用范围更广;strcpy是属于字符串拷贝,仅适用于字符串类型的拷贝。
[*]memcpy不会查抄字符串结束符 \0;而会主动拷贝直到碰到 \0,并包罗 \0 本身
memcpy:
char a[] = "ciallo";
char b[] = "0d00";
memcpy(a, b, 4);
printf("%s\n", a);
return 0;
// 输出结果 0d00lo int a[] = { 1,2,3,4 };
int b[] = { 100,200 };
memcpy(a, b, sizeof(int) * 2);
for (int i = 0;i < sizeof(a) / sizeof(a);i++) {
printf("%d ", a);
}
return 0;
// 输出结果 100 200 3 4 strcpy:
char a[] = "ciallo";
char b[] = "0d00";
strcpy(a, b);
printf("%s\n", a);
return 0;
// 输出结果 0d00 数组越界问题:
char src[] = "HelloWorld";// 10个字符(含 '\0')
char dest; // 空间太小
strcpy(dest, src);// ❌ 越界写入
printf("dest = %s\n", dest); // 有可能崩溃或显示乱码编译型语言与解释型语言不同
https://i-blog.csdnimg.cn/direct/fdd86fd560ec44eeb40f113672400577.png
calloc、malloc、realloc函数的区别及用法
calloc、malloc、realloc函数的区别及用法-CSDN博客
二、数据结构与算法
顺序结构(数组)和链式结构(链表)有什么不同,应用在哪些场景?
https://i-blog.csdnimg.cn/direct/ef305693b04143f6a5377dd82c66d30d.png
https://i-blog.csdnimg.cn/direct/2e23cd3c72534264a5286ef4f1b8cd5e.png
队列和栈有什么不同,应用场景有哪些?
https://i-blog.csdnimg.cn/direct/1d9e170990ba4b559639a11253907d1b.png
https://i-blog.csdnimg.cn/direct/3a29ba3568c144618e761a652c1c3e5b.png
三、stm32
嵌入式面试八股文总结(恒久更新)-CSDN博客
一个开关控制一个LED灯开关,由stm32做主控,按下按键,灯会时亮时不亮,缘故起因由那些?
1️⃣ 按键抖动,按键没弄消抖
2️⃣ 检测方式不对(没有边沿触发)
3️⃣ 中断触发多次(假如你用了 EXTI)
RAM
GPIO工作模式
stm32入门-----GPIO口输出的学习与使用(上)_stm32 ll gpio-CSDN博客https://i-blog.csdnimg.cn/direct/af29ef9fec254012adf600e8b5f55010.png
模式编号模式名称功能分类输出类型上下拉设置应用场景1浮空输入输入无无通用输入,外接信号控制电平2上拉输入输入无上拉默认高电平的输入,防止悬空3下拉输入输入无下拉默认低电平的输入,防止悬空4模仿输入(模仿模式)模仿无无ADC/DAC,降低功耗5推挽输出输出推挽可配数字输出,如控制LED6开漏输出输出开漏外部上拉多主装备通信,如 I2C7推挽复用输出复用推挽可配外设功能,如 USART、SPI8开漏复用输出复用开漏外部上拉外设功能,如 I2C、Open-Drain 总线 UART和USART区别
比力项UART(通用异步收发器)USART(通用同步/异步收发器)全称Universal Asynchronous Receiver/TransmitterUniversal Synchronous/Asynchronous Receiver/Transmitter通信方式仅支持异步通信支持异步和同步通信是否需要时钟否同步通信时需要外部或内部时钟起始/克制位需要(用于异步同步)异步时需要,同步模式下不需要通信速率一般较慢(受限于异步机制)同步模式下可更快应用场景串口调试、GPS模块、蓝牙等常见串口外设除异步串口外,也用于高速同步外设通信硬件复杂度简单稍复杂(多了同步部分)兼容 UART—✅ 是 中断和DMA不同
[*]DMA:是一种无须CPU的到场,就可以让外设与体系内存之间进行双向数据传输的硬件机制,使用DMA可以使体系CPU从实际的I/0数据传输过程中摆脱出来,从而大大进步体系的吞吐率。
[*]中断:是指CPU在执行步伐的过程中,出现了某些突发事件时,CPU必须暂停执行当前的步伐,转去处置处罚突发事件,处置处罚完毕后CPU又返回源步伐被中断的位置并继承执行。
总而言之中断和DMA的区别就是:DMA不需CPU到场,而中断是需要CPU到场的。
IIC读写时序
stm32入门-----软件I2C通讯_i2c两个雷同地址-CSDN博客
https://i-blog.csdnimg.cn/direct/7b82526b3bad4ec3a2e3a9ee5144c173.png
https://i-blog.csdnimg.cn/direct/3a8d5fd141f14f0e9e20e0384c87ab88.png
时序
[*]规定SCL高电平的时为工作状态,低电平为休息状态。在SCL工作状态时间,保证SDA保持处于高电平(数据1)或低电平(数据0)
[*]空闲状态下,SCL和SDA都是高电平状态
[*]起始的时间SCL处于高电平,SDA由高电平降低到低电平;结束的时间SCL处于高电平,SDA由低电平会到高电平
[*]应答位0表现收到,1表现没收到
[*]第一组数据(字节),的前7为表现装备地址,末了一位表现操作位,1是读,0是写
https://i-blog.csdnimg.cn/direct/95b708e4032f435e88cadcc3ac2994f5.png
SPI
stm32入门-----SPI通讯协议_stm32spi发送数据-CSDN博客
https://i-blog.csdnimg.cn/direct/94ab1b1f1fbb4eb19fa91d3df580dde5.png https://i-blog.csdnimg.cn/direct/a1b603e8ad894351939accc6a71bce0f.png
工作模式
https://i-blog.csdnimg.cn/direct/f61e9afab38344b3be9d3120ca1a0c99.png
FreeRtos调度算法
https://i-blog.csdnimg.cn/direct/7b2075b28f274b72a44600a0254e5e9a.png
[*]抢占式:高优先级使命可以打断低优先级的使命的执行(顺应于优先级不同的使命)。
[*]时间片轮转:雷同优先级的使命以雷同的时间片(1ms)去运行,时间片耗尽后就强制退出去执行其他使命。
[*]协作式调度:当使用vtaskdelay() 去是否CPU的资源让其他使命来运行,如可用信号量,互斥量实现。(这种方式很少用)
FreeRtos使命的状态
[*]停当态:使命创建的时间就进入到停当态
[*]运行态:使命的代码运行的时间
[*]阻塞态:使命在等候信号量、互斥量的时间会进入,同步过程
[*]挂起态:使用vTaskSuspend() 函数去进入到挂起,背面可以手动去使vTaskResume()叫醒
https://i-blog.csdnimg.cn/direct/5671288511624cf1b43a13a49ddb62f1.png
FreeRtos使命同步方式
FreeRtos------信号量、互斥量和事件组_信号量重复give-CSDN博客
FreeRtos-----队列_freertos队列发送数据-CSDN博客
[*]队列:同步的同时也可以通报数据(天然的生产者消耗者模子)
[*]信号量:分为二进制信号量(实现共享资源的访问)和计数信号量(实现手动生产者消耗者模子)
[*]互斥量:实现共享资源的安全访问,又叫做锁
[*]事件组:可以实现多个使命的关照,一次性去关照多个使命
[*]使命关照:轻量级的使命同步方式,TCB,不需要创建就可以使用,一般用于一对一的通讯(上面的四种都是用于多对多的通讯)
https://i-blog.csdnimg.cn/direct/15c65126d6d547e685b5738339b327bf.png
环形缓冲区(KFIFO)
环形缓冲区并不是指真正物理意义上的一个环,只是把一个存储区(比如uint8_t array),通过步伐上的计划实现一个环形的结果,对于这个存储区要实现"先入先出"的特性。这样做的好处就是减少了内存碎片和动态分配内存的体系开销
https://i-blog.csdnimg.cn/direct/e0098389d8b94211923f8f57c24e475c.png
FIFO
四、操作体系Linux
基本指令
FreeRtos和Linux的不同
✅ 1. 及时性
[*] FreeRTOS:及时操作体系,使命调度及时,相应快,适合对时效性要求高的应用。
[*] Linux:默认不是及时体系,相应存在耽误(可打 RT 补丁提升)。
✅ 2. 体系体积
[*] FreeRTOS:非常小,几 KB ~ 几十 KB,就能运行。
[*] Linux:体系庞大,至少几 MB 起步,还需文件体系等。
✅ 3. 资源需求
[*] FreeRTOS:适合资源受限的 MCU,如 STM32。
[*] Linux:需要 MMU、更多 RAM 和存储,如 Cortex-A 芯片。
✅ 4. 编程模子
[*] FreeRTOS:无进程概念,只有使命(线程)。
[*] Linux:支持多进程、多线程,功能更完整。
✅ 5. 装备支持
[*] FreeRTOS:需手动添加驱动,功能有限。
[*] Linux:驱动丰富,支持 USB、文件体系、网络等。
✅ 6. 启动速率
[*] FreeRTOS:极快,几毫秒~几十毫秒。
[*] Linux:慢,通常几秒乃至更久。
✅ 7. 应用场景
[*] FreeRTOS:嵌入式、IoT、工业控制、小型装备。
[*] Linux:智能装备、边沿计算、图像处置处罚、AI。
Windows和Linux的多进程有什么不同
https://i-blog.csdnimg.cn/direct/873d057deef6481c9951025c67d96ad7.png
动态库和静态库区分与应用
界说:
项目静态库(Static Library)动态库(Dynamic Library)扩展名.a(Linux)、.lib(Windows).so(Linux)、.dll(Windows)链接方式编译时链接运行时链接(步伐运行时加载)是否复制历步伐✅ 会复制(编译时嵌入)❌ 不复制,步伐运行时依赖外部库可执行文件大小大(包罗库的代码)小(仅包罗引用信息) 动态库和静态库的区别:
维度静态库动态库链接时间编译时运行时占用空间可执行文件大可执行文件小,库可共享更新维护需重新编译整个步伐更新库文件即可,无需重新编译启动速率快(不依赖外部库)稍慢(运行时加载库)依赖性独立依赖外部库文件调试方便性更容易调试动态调试更复杂 动态库(Dynamic Library,也叫共享库,如 .so / .dll)虽然带来了模块化、节省内存、便于更新等优点,但它也有一些缺点和使用上的注意点。下面我们来具体看看:
https://i-blog.csdnimg.cn/direct/35ed5555c7b749faa8e60fb5a1e363c1.png
https://i-blog.csdnimg.cn/direct/15753b8f56644849908dfa318edfcdb6.png
页:
[1]