volatile关键字
在C和C++中,volatile
关键字用于告诉编译器某些特定的变量可能会在无意中被修改,从而防止编译器优化掉相关代码。当我们使用声明为volatile
类型的变量时,表示变量的值是随时可能发生变化的,并且需要特别小心地处理。
主要有以下几种情况需要使用volatile
关键字:
-
位域
当使用volatile
关键字定义位域时,保证相应的存储单元不被优化器优化,并且在访问每个位域时都会从该内存位置重新读取数据。由于位域只能定义为整型或枚举类型,因此如果一个结构体里面有位域成员,需要将整个结构体定义为volatile
类型才能保证可靠性。 -
中断服务程序中修改的变量
在一些嵌入式系统中,硬件设备产生中断信号后,中断服务程序需要马上执行,这时需要使用volatile
关键字来声明中断服务程序修改的变量,以免编译器优化掉相关代码。 -
多线程环境中被多个线程共享的变量
当多个线程访问同一个变量时,各线程之间对共享变量进行的操作可能不遵循程序的代码顺序,如果没有使用volatile
关键字,编译器可能会进行代码重排,导致程序运行结果与预期不符。
综上所述,volatile
关键字的作用是告诉编译器某个变量是易变的,需要特殊处理,以便正确地反映该变量在程序中的实际状态,避免因优化掉相关代码而引发的不可预期的问题。
举个例子:
下面是一个在嵌入式系统中的使用volatile
关键字的例子:
#include <stdio.h>
// 定义一个计时器
volatile unsigned int timer = 0;
// 模拟硬件中断服务程序,每隔一秒钟定时器值加1
void interrupt_service_routine() {
while (1) {
// 将定时器值加1
timer++;
// 模拟延时
for (int i = 0; i < 0xFFFFF; i++);
}
}
// 主函数,定时查询定时器的值
int main() {
// 启动中断服务程序
interrupt_service_routine();
// 定时查询定时器的值并输出
while (1) {
printf("Timer = %u\n", timer);
// 模拟延时
for (int i = 0; i < 0xFFFFF; i++);
}
return 0;
}
在上面的代码中,我们定义了一个volatile
类型的变量timer
,表示这个变量可能会被不同线程或中断服务程序所修改。然后,我们在一个死循环中不停地查询这个变量的值并输出,在主循环中也增加了一个模拟延时的操作。
而在interrupt_service_routine()
函数中,则通过一个死循环不停地将timer
变量的值加1,模拟每隔1秒钟就会产生中断并对该变量进行修改的情况。
因为timer
是一个易变的变量,可能被interrupt_service_routine()
函数随时修改,因此我们需要在声明该变量时使用volatile
关键字来告诉编译器进行特殊处理,并保证查询到的值是实际的最新值,避免了不可预期的运行结果。