volatile 说明及用法

张开发
2026/4/9 5:09:56 15 分钟阅读

分享文章

volatile 说明及用法
一、功能一句话告诉编译器这个变量可能被 ”外部“ 改变禁止优化每次访问都必须从 ”内存 “读写。这里的 “外部”不要从“文件”或“模块”理解而是从 ”执行过程“ 理解有些变量的变化不受你这段代码的执行顺序控制如下所示常见情况使用场景硬件寄存器值由硬件改变常用中断函数ISR 修改变量 常用多线程其他线程修改DMA / 外设直接改内存 总结编译器无法确定是谁改了它也不知道什么时候改的。例1硬件寄存器假设你读取一个硬件状态寄存器地址0x40001没有volatile时// 没有使用 volatile 修饰 uint32_t* status_reg (uint32_t*)0x4000; while ((*status_reg 0x01) 0) { // 等待硬件把bit0置1 }编译器看到循环里没修改*status_reg会优化成以下代码uint32_t temp *status_reg; // 只读一次 while ((temp 0x01) 0) { // 永远用temp判断死循环 }结果当硬件改了这个地址的值但程序永远看不见。2有volatile时volatile uint32_t* status_reg (uint32_t*)0x4000;结果编译器每次都老老实实去读0x4000硬件改的值就能被看到。例2中断服务函数int flag 0; // 普通变量 void interrupt_handler() { flag 1; // 中断里修改 } void main() { while (flag 0) { // 主循环等待 // do something } }1没有volatile时编译器优化flag 在循环里没被改过于是把 flag 读到寄存器永远用寄存器判断中断改的是内存里的 flag程序看不见 → 死循环。2有volatile时编译器每次循环都去读内存里的 flag中断改的值就能被看见。例3多线程其他线程修改volatile 不是为多线程同步设计的。volatile 只能保证 每次读取都会从内存取值不会被编译器优化掉但它不能保证多个线程同时修改时结果正确例如自增出错操作的完整性一个操作可能被打断线程之间的执行顺序也就是说 它只能解决“看不见变化”解决不了“改不乱”例4DMA / 外设直接改内存volatile 只保证“会去读内存”但不保证“读到的是最新数据”。

更多文章