嵌入式开发中的一些关键字

嵌入式开发中的一些关键字
THEDIvolatile
volatile关键字作用
禁止编译器优化
告知编译器该变量可能被“外部因素”修改(如硬件、中断、多线程等),每次访问必须直接读写内存,而非依赖寄存器缓存或优化掉“冗余”操作。确保内存可见性
强制程序按代码顺序执行对变量的读写操作,避免因编译器重排指令导致的意外行为。
volatile使用场景
- 直接访问硬件寄存器(某个外设等)
1 | volatile uint32_t *status_reg = (volatile uint32_t*)0x40021000; |
如果不适用volatile编译器的优化:
缓存到寄存器
编译器发现status_reg
的值在循环中没有被修改(代码中未显式修改),于是将*status_reg
第一次读取的值缓存到寄存器中,后续循环直接复用寄存器值,不再从内存读取。优化结果:
生成的汇编代码可能如下:1
2
3
4
5
6
7; 第一次读取 *status_reg 到寄存器 eax
mov eax, [0x40021000]
loop:
test eax, 0x01 ; 检查寄存器 eax 的值
jnz exit_loop ; 如果状态位为 1,退出循环
jmp loop ; 继续循环问题:硬件修改了状态寄存器的值,但程序始终读取的是寄存器
eax
中的旧值,导致死循环!
- 中断服务程序中修改的全局变量
主循环中访问的全局变量可能被 ISR 异步修改,即可能同时访问,需用 volatile
确保主循环能感知变化。
1 | volatile bool data_ready = false; |
- 多线程/多任务共享变量
在无锁或简单同步的场景中,volatile
可防止编译器优化掉对共享变量的访问。但需注意:volatile
不保证原子性,复杂场景仍需结合锁或原子操作。
- 防止编译器优化空循环
在延时或等待硬件响应的循环中,编译器可能优化掉“无意义”的空循环。
1 | volatile int i; |
extern “C”
在嵌入式开发中,extern "C" {}
的作用是告诉 C++ 编译器以 C 的方式来处理括号中的代码,从而防止 C++ 的名称修饰(Name Mangling)。
使用场景
当你在 C++ 源文件中调用 C 语言写的函数或头文件 时,就需要用 extern "C"
来保证链接正常。
为什么需要 extern "C"
?
C++ 支持函数重载,因此会对函数名进行“名称修饰”,比如 void foo(int)
可能会变成 _Z3fooi
。
而 C 编译器不会做名称修饰,函数名就是原始的,比如 foo
。
所以如果你直接在 C++ 里调用 C 的函数,会因为找不到名字而链接失败。
因为源文件是CPP
使用方法
- 使用方法1(不常用):用C写的头文件,在C++中使用,分开
2.使用方法2(推荐使用):直接将extern “C”放在头文件中
1 |
|
__cplusplus
是一个由 C++ 编译器自动定义的宏,表示当前代码是用 C++ 编译器在编译。
- 如果是 C++ 编译器:
#ifdef __cplusplus
成立,里面的内容会被编译。- 如果是 C 编译器:
__cplusplus
没有定义,内容就会被忽略。