一、C语言篇
1.typedef有什么作用
用于为现有数据类型创建别名。通过 typedef 可以简化复杂类型的声明,提高代码可读性和可维护性。
对于指针、结构体或函数指针等复杂类型,typedef 可以隐藏细节,使代码更清晰。例如
c
typedef int (*FuncPtr)(int, int); // 定义函数指针类型别名
FuncPtr add_func = &add; // 使用别名声明变量
c
typedef struct { int x, y; } Point; // 隐藏结构体标签
Point p = {1, 2};
例如常见的 size_t,uint8_t等关键字。
2.static 有什么作用
在 C 语言中,static 关键字根据上下文的不同,可以用于变量或函数,主要作用是控制作用域和生命周期。
当 static 用于变量时,变量的作用域限制在当前文件或函数内,其他文件或作用域无法访问。这可以避免命名冲突。
当 static 用于函数时,函数的作用域限制在当前文件内,其他文件无法调用。这有助于封装和模块化代码。
!!注意,static修饰的变量,其核心逻辑是变量由栈区转移到了静态数据区。而修饰函数未改变其存储区域而是改变了函数的链接属性。
3.内联函数和宏函数的作用
宏函数是预处理阶段的文本替换,内联函数是编译阶段的代码嵌入
内联函数(inline函数)的主要作用是减少函数调用的开销,提升程序执行效率。其核心机制是通过编译器将函数体直接嵌入调用点,避免常规函数调用时的压栈、跳转和返回操作。
| 特性 | 宏函数(#define) | 内联函数(inline) |
|---|---|---|
| 处理阶段 | 预处理阶段(编译前) | 编译阶段 |
| 本质 | 纯文本替换,无类型检查、无函数调用逻辑 | 编译器优化后的 "嵌入式函数",有完整函数特性 |
| 类型安全 | 无类型检查,容易因类型不匹配出隐蔽错误 | 严格的类型检查(参数、返回值),和普通函数一致 |
| 作用域 | 全局有效(除非用 #undef),无作用域限制 | 遵循函数作用域规则(如 static inline 仅限当前文件) |
| 求值次数 | 传参参数会被多次求值,例如++a(易出逻辑错误) | 参数仅求值一次,和普通函数一致 |
| 调试难度 | 无法调试(预处理后已替换,无函数调用栈) | 可调试(部分编译器支持),有函数调用栈信息 |
| 递归支持 | 不支持递归(预处理阶段无法处理递归替换) | 支持递归(但编译器可能拒绝内联递归函数) |
| 内存开销 | 无函数调用栈开销,但重复替换易导致代码膨胀 | 编译器可自主决定是否内联,能平衡开销与性能 |
4.指针的大小
指针的大小和编译器的位数有关。在32bit位系统下指针的大小是4个字节(32bit = 4byte),64bit位系统下指针的大小则是8个字节(64bit = 8byte)。指针的大小是固定的,和指针的类型没有关系。
5.野指针
野指针定义:指向不可用内存的指针。
为什么会产生野指针?
1.当指针被创建时,没有给指针赋值。
2.当指针被free或delete后,没有把指针赋值为NULL,这个时候指针也为野指针。
3.当指针越界的时候也算野指针。
6.sizeof与strlen区别
属性:sizeof是C语言的运算符,结果在编译阶段就可以确定;strlen是C语言的库函数,需要在运行时才能计算出结果。
作用:sizeof 用于获取数据类型或变量占用的内存大小(以字节为单位);strlen用于计算字符串的长度(不包括结尾的空字符10')。
参数:sizeof的参数可以是数据的类型,也可以是变量;而strlen只能以结尾为'\0'的字符串作参数
7.volatile的作用
volatile 是 C 语言中的一个关键字,用于修饰变量,告诉编译器该变量可能被意外修改,避免编译器优化导致的问题。它通常用于以下场景:
- 硬件寄存器或内存映射的 I/O。
- 多线程或中断服务程序中共享的变量。
- 被信号处理函数修改的变量。
!!volatile可以与const结合,表示变量不能被程序改变,但是可以比外部修改。多用于硬件寄存器的映射的变量。
8.左值和右值
左值(lvalue)和右值(rvalue)是C++中用于描述表达式类别的术语,其核心区别在于表达式能否被赋值或取地址。
- 左值 :通常指可以出现在赋值语句左侧的表达式,具有持久的内存地址,能够被取地址(如变量、对象或解引用后的指针)。
- 右值:通常指只能出现在赋值语句右侧的表达式,是临时对象或字面量,没有持久的内存地址(如字面量、临时对象或返回右值引用的函数调用)。
二、MCU硬件篇
1.字节对齐
字节对齐(Byte Alignment)是计算机系统中数据在内存中存储的一种优化方式,要求数据的起始地址必须是某个特定值(通常是其自身大小或系统字长的整数倍)。对齐的目的是提升内存访问效率,避免因未对齐访问导致的性能损失或硬件异常。
部分的性能紧张的mcu不支持字节不对齐的访问。
具体看我博客中的 字节对齐的总结。
2.数据总线和地址总线
数据总线根据地址总线中对应的地址,去获取地址中的数据。
数据总线的字节位数意味着这个芯片的最大带宽,即是一次性能够获取多少的数据。
地址总线的字节数则意味着芯片的最大地址长度。例如0x00;两位的带宽,意味着只能寻找最大0xFF的数据。
3.什么是大端模式和小端模式
计算机系统中以字节(8bit)为存储单元,也就是每个地址单元对应一个字节,C语言中的int、short等类型数据大小大于一字节,所以就要考虑到多字节类型数据在内存中的字节排序问题,也就是大端模式和小端模式,介绍如下:
小端模式:数据的低位存放在低地址中,数据的高位存放在高地址中。如存储0x12 34 56 78,小端存储时情况如下:
低地址 --------------------> 高地址
0x78 | 0x56 | 0x34 | 0x12
大端模式:数据的高位存放在低地址中,数据的低位存放在高地址中。如存储0x12 34 56 78,大端存储时情况如下:
低地址 --------------------> 高地址
0x12 | 0x34 | 0x56 | 0x78
4.中断和异常有什么区别
中断通常由外部硬件设备触发,例如键盘输入、定时器到期或网络数据到达。中断是异步的,意味着它可以在任何时候发生,与当前执行的指令无关。
异常通常由CPU执行指令时检测到的错误或特殊情况触发,例如除以零、非法指令或页错误。异常是同步的,意味着它与当前执行的指令直接相关。