c语言中的volatile

本文深入探讨了volatile关键字在多任务环境中的应用,解释了如何通过volatile禁止编译器优化,确保变量读写的可见性和一致性。此外,还介绍了volatile在中断服务程序、多任务共享标志以及存储器映射硬件寄存器中的作用。
      volatile总是与优化有关,编译器有一种技术叫做数据流分析,分析程序中的变量在哪里赋值、在哪里使用、在哪里失效,分析结果可以用于常量合并,常量传播等优化,进一步可以死代码消除。但有时这些优化不是程序所需要的,这时可以用volatile关键字禁止做这些优化,volatile的字面含义是易变的,它有下面的作用:     1 不会在两个操作之间把volatile变量缓存在寄存器中。在多任务、中断、甚至setjmp环境下,变量可能被其他的程序改变,编译器 自己无法知道,volatile就是告诉编译器这种情况。
2 不做常量合并、常量传播等优化,所以像下面的代码:   volatile int i = 1;   if (i > 0) ...     if的条件不会当作无条件真。     3 对volatile变量的读写不会被优化掉。如果你对一个变量赋值但后面没用到,编译器常常可以省略那个赋值操作,然而对Memory Mapped IO的处理是不能这样优化的。     有人说volatile可以保证对内存操作的原子性,这种说法不大准确,其一,x86需要LOCK前缀才能在SMP下保证原子性,其二,RISC根本不能对内存直接运算,要保证原子性得用别的方法,如atomic_inc。     对于jiffies,它已经声明为volatile变量,我认为直接用jiffies++就可以了,没必要用那种复杂的形式,因为那样也不能保证原子性。     你可能不知道在Pentium及后续CPU中,下面两组指令     inc jiffies   ;;   mov jiffies, %eax   inc %eax   mov %eax, jiffies     作用相同,但一条指令反而不如三条指令快。    ----------------------------------------------------------------------------------------------------------     一般这个修饰符用来告知编译器,被修饰的变量是个“易变的”变量(volatile的本意是“易变的”),防止编译器进行优化。将变量加上volatile修饰,则编译器保证对此变量的读写操作都不会被优化。    1、中断服务程序中修改的供其它程序检测的变量需要加volatile;    2、多任务环境下各任务间共享的标志应该加volatile;    3、存储器映射的硬件寄存器通常也要加volatile说明,因为每次对它的读写都可能有不同意义
### C语言中 `volatile` 关键字的作用和使用场景 #### 1. **`volatile` 的基本作用** 在 C 语言中,`volatile` 是一种类型限定符,用来告知编译器某个变量的值可能随时会被外部因素更改。这意味着编译器不能对该变量进行任何优化操作,例如将其存储在寄存器中或者假设它的值不会发生变化[^4]。 当一个变量被声明为 `volatile` 后,每次访问这个变量时都会直接从内存中读取最新值,而不是依赖于之前缓存在寄存器或其他地方的数据。这种行为对于多线程环境、硬件交互以及信号处理等场合尤为重要[^3]。 #### 2. **语法与用法** `volatile` 可以通过以下方式来定义变量: ```c volatile int myVariable; int volatile anotherVar; ``` 上述两种写法功能相同,均表示 `myVariable` 和 `anotherVar` 被标记为易失型变量。需要注意的是,`volatile` 仅能用于修饰变量,而无法应用于函数或者其他类型的实体。 #### 3. **典型使用场景** ##### (1) 中断服务程序 在一个嵌入式系统中,如果某些全局变量可以由中断服务程序修改,则这些变量应当声明为 `volatile` 类型。这样能够防止由于编译器优化而导致主线程看不到最新的变量值的情况发生。 示例代码: ```c volatile uint8_t interruptFlag = 0; void ISR() { interruptFlag = 1; // 中断触发后设置标志位 } // 主循环不断检测标志位状态 while (!interruptFlag); ``` 此处如果没有加上 `volatile` 定义的话,在许多情况下编译器会认为 `interruptFlag` 不会发生变化从而对其进行优化,最终可能导致死循环等问题。 ##### (2) 多线程编程 即使是在标准 C++ 或 POSIX 线程库下开发的应用软件里头,只要涉及到多个独立运行路径共享同一份数据资源的情形之下,也推荐采用此机制确保一致性[^2]。 注意:尽管如此,单靠 `volatile` 并不足以解决所有同步需求;更复杂的并发控制仍需借助锁机制实现。 ##### (3) 访问 I/O 寄存器 针对特定地址空间内的特殊用途单元格(如设备控制器的状态字段),程序员往往希望每一次查询都能反映当前实际状况而非先前副本的内容——此时正是运用 `volatile` 发挥效用之时[^1]。 例子展示如何正确配置串口通信参数: ```c #define UART_STATUS (*(volatile unsigned char *)0x1F0) if ((UART_STATUS & TX_READY_MASK) != 0){ sendByte(); } ``` 这里假定微处理器内部结构已知,并且可以通过指针形式定位到相应位置上的比特组合完成判断动作。 --- ### 总结 综上所述,`volatile` 在 C 编程中有助于保障那些受外界影响频繁变动对象的安全性和可靠性。然而值得注意的一点在于,虽然它可以阻止不必要的指令重排现象出现,但对于真正的原子级操作而言还是不够充分,必要时候还得依靠其他手段加以补充完善。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值