ZHCUAV8W january 1998 – march 2023 66AK2E05 , 66AK2H06 , 66AK2H12 , 66AK2H14 , AM1705 , AM1707 , AM1802 , AM1806 , AM1808 , AM1810 , AM5K2E04 , OMAP-L132 , OMAP-L137 , OMAP-L138 , SM470R1B1M-HT , TMS470R1A288 , TMS470R1A384 , TMS470R1A64 , TMS470R1B1M , TMS470R1B512 , TMS470R1B768
C/C++ 编译器在所有模式下都支持 volatile 关键字,但 。此外,在 C89、C99、C11 和 C++ 的宽松 ANSI 模式下支持 __volatile 关键字。
volatile 关键字指示编译器如何访问变量,这要求编译器不得投机取巧地优化涉及该变量的表达式。例如,外部程序、中断、另一个线程或外围设备也以访问该变量。
编译器会使用数据流分析来确定访问是否合法,从而尽可能消除冗余的存储器访问。不过,一些存储器访问可能在编译器未看到的方面比较特殊,在这类情况下,您应当使用 volatile 关键字来防止编译器优化掉某些重要内容。对于已声明为 volatile 的变量,编译器不会优化掉对该变量的任何访问。volatile 读取和写入的次数将与 C/C++ 代码中的完全相同,不多不少而且顺序也完全相同。
任何可能由明显程序控制流程外部的事物(例如中断服务例程)进行修改的变量必须声明为 volatile。这会告诉编译器,中断函数可能会随时修改该值,因此编译器不应执行会更改该变量的编号或访问顺序的优化。这就是 volatile 关键字的主要用途。在下述示例中,循环旨在等待位置被读取为 0xFF :
unsigned int *ctrl;
while (*ctrl !=0xFF);
不过,在此示例中,*ctrl 是循环不变量表达式,因此循环会优化为单个存储器读取。若要获取所需结果,应将 ctrl 定义为:
volatile unsigned int *ctrl;
其中,*ctrl 指针旨在引用一个硬件位置,例如中断标志。
访问表示存储器映射外围设备的存储器位置时,也必须使用 volatile 关键字。此类存储器位置可能会以编译器无法预测的方式更改值。这些位置可能会在被访问时、或者当其他存储器位置被访问时或者出现某些信号时发生改变。
在调用 setjmp 的函数中,如果局部变量的值需要在发生 longjmp 时保持有效,则 volatile 也必须用于局部变量。
#include <stdlib.h>
jmp_buf context;
void function()
{
volatile int x = 3;
switch(setjmp(context))
{
case 0: setup(); break;
default:
{
/* We only reach here if longjmp occurs.因为 x 的生命周期在 setjmp 之前开始并持续至 longjmp,C 标准要求将 x 声明为 "volatile"。*/
printf("x == %d\n", x);
break;
}
}
}