Volatile
Volatile : (意思是 不稳定的)限定一个对象可被外部进程(操作系统、硬件或并发线程等)改变,声明时的语法如下:
int volatile nVint
; 这个说明 让程序每次读取nVint 真正的值。
volatile int i=10;
int a = i;
... // 这里的代码可能回改变i 的值
// 其他代码,并未明确告诉编译器,对 i 进行过操作
int b = i;
在上面 volatile 指出 i 是随时可能发生变化的,每次使用它的时候必须从 i的地址中读取,因而编译器生成的汇编代码会重新从i的地址读取数据放在 b 中。而优化做法是,由于编译器发现两次从 i读数据的代码之间的代码没有对 i 进行过操作,它会自动把上次读的数据放在 b 中。而不是重新从 i 里面读。这样以来,如果 i是一个寄存器变量或者表示一个端口数据就容易出错(就是直接定义int i = 10;
),所以说 volatile 可以保证对特殊地址的稳定访问。
像上面这种声明方式,是不能达到最高效的,因为它们的值随时会改变,系统在需要时会经常读写这个对象的值。因此常用于像中断处理程序之类的异步进程进行内存单元访问。
#include <stdio.h>
void main()
{
int i = 10;
int a = i;
printf("i = %d", a);
// 下面汇编语句的作用就是改变内存中 i 的值
// 但是又不让编译器知道
__asm{
mov dword ptr [ebp-4], 20h
}
int b = i;
printf("i = %d", b);
}
上面的代码只能在VC 上的才能运行出效果,我在VS2017上试过,都是经过编译器优化后的值。
在VC 中的 Debug 版本模式运行程序,输出结果如下:
i = 10
i = 32
在 Release
版本模式运行程序,输出结果如下:
i = 10
i = 10
下面是加了volatile 关键字后,下面代码是在老版编译器上,说明一下。
#include <stdio.h>
void main()
{
volatile int i = 10;
int a = i;
printf("i = %d", a);
__asm {
mov dword ptr [ebp-4], 20h
}
int b = i;
printf("i = %d", b);
}
分别在 Debug 和 Release 版本运行程序,输出都是:
i = 10
i = 32
哪样的岗位喜欢考查这个关键字呢?
在我看来,学习嵌入式编程,有些面试官就喜欢出这个关键字。
关键字volatile有什么含意? 这里有三个场景。
volatile的本意是“易变的” 由于访问寄存器的速度要快过RAM,所以编译器一般都会作减少存取外部RAM的优化,但有可能会读脏数据。当要求使用volatile 声明的变量的值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。而且读取的数据立刻被保存。
精确地说就是,优化器在用到这个变量时必须每次都小心地重新从内存里读取这个变量的值,而不是使用保存在寄存器里的备份。 下面是volatile变量的几个例子:
- 并行设备的硬件寄存器(如:状态寄存器)
- 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)
- 多线程应用中被几个任务共享的变量
一般地,volatile用在如下的几个地方:
- 中断服务程序中修改的供其它程序检测的变量需要加volatile;
- 多任务环境下各任务间共享的标志应该加volatile;
- 存储器映射的硬件寄存器通常也要加volatile说明,因为每次对它的读写都可能由不同意义;