volatile关键字和const一样都是一种类型修饰符,用它修饰过的变量表示可以被某些编译器未知的因素更改,比如操作系统、硬件或者是其它线程等。
该关键字是不希望被编译器优化,从而达到稳定访问内存的目的。
示例代码:
#include<stdio.h>int main()
{int i = 10;int j = i;int k = i;return 0;
}
在程序运行起来后,查看反汇编(两个版本):
Debug
Release --- 进行了代码优化
此时编译器对代码进行了优化,在 int j = i ; int k = i; 这两条语句中,i 没有被作为左值,编译器认为 i 值没有被修改,所以从内存中取出 i 的值赋值给 j 后,这个值并没有被丢掉,而是继续执行了下一条语句,对 k 进行赋值,此时,编译器不会生成新的汇编代码重新从内存中取 i 的值,提高了效率。(Debug)
与上述代码做对比,添加 volatile 后 --- 代码:
#include<stdio.h>int main()
{volatile int i = 10;int j = i;int k = i;return 0;
}
在程序运行起来后,查看反汇编(两个版本):
Debug
Release --- 进行了代码优化
volatile 关键字告知编译器 i 可能随时发生变化,即每一次使用 i 值的时候,都必须从内存中读取出 i 的值。所以编译器生成的汇编代码会重新从 i 的地址处读取数据放在 k 中。(Debug)
由上述现象可知,如果 i 时一个寄存器变量或者表示一个端口数据或者是多个线程的共享数据,就非常容易发生错误。所以 volatile 可以保证对特殊地址的稳定访问。
思考:const volatile int a = 10; // 该条语句会不会报错
const --- 要求你不要进行写入
volatile --- 在读取数据的时候每次都要从内存中读取
以上两者并不冲突,该代码不会报错
volatile变量的⼏个例⼦:
<1> :并⾏设备的硬件寄存器(如:状态寄存器)
<2>:⼀个中断服务⼦程序中会访问到的⾮⾃动变量(Non-automatic variables)
<3>: 多线程应⽤中被⼏个任务共享的变量