ZHCU876Z July 2001 – October 2023 SM320F28335-EP
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;
}
}
}
如果存储器映射配置为单个统一空间,则可以使用 --unified_memory 选项;此选项允许编译器可以为大多数 memcpy 调用和结构赋值生成更高效的指令。即使在统一存储器时,一些外设的存储器以及一些与这些外设关联的 RAM 都只在数据存储器中分配。 如果启用了 –unified_memory,您可以通过将这些符号声明为 volatile,阻止程序通过存储器地址访问特定的符号。