1.volatile 的简介:
volatile 的作用:当对象的值可能在程序的控制或检测之外被改变时,应该将该对象声明为 volatile,告知编译器不应对这样的对象进行优化。volatile 关键字修饰变量后,提醒编译器它后面所定义的变量随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据。如果没有 volatile 关键字,则编译器可能优化读取和存储,可能暂时使用寄存器中的值,如果这个变量由别的程序更新了的话,将出现不一致的现象。
使用 volatile 关键字试图阻止编译器过度优化,volatile 主要作用如下:
2.volatile 的作用:
C++
volatile int i=10;
int a = i;
...
// 其他代码,并未明确告诉编译器,对 i 进行过操作
int b = i;
volatile 修饰 i 后,表明每次使用 i 时必须从 i 的地址中读取,因而编译器生成的汇编代码会重新从 i 的地址读取数据放在 b 中。如果不加 volatile,编译器会进行优化,编译器发现两次从 i 读数据的代码之间的代码没有对 i 进行过操作,它会自动把上次读的数据放在 b 中,而不是重新从 i 里面读,如果 i 是一个寄存器变量,则 i 可能已经被外部程序进行改写,因此 volatile可以保证对特殊地址的稳定访问。
C++
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
int ra = 0;
int rb = 0;
ra = 0x1111;
ra = 0x2222;
ra = 0x3333;
rb = ra;
printf("%d\n", ra);
return 0;
}
我们使用编译器优化:
shell
g++ -S -O3 test.cpp -o test
查看编译后的代码为:
C
0000000000000560 <main>:
560: 48 83 ec 08 sub $0x8,%rsp
564: ba 33 33 00 00 mov $0x3333,%edx
569: bf 01 00 00 00 mov $0x1,%edi
56e: 31 c0 xor %eax,%eax
570: 48 8d 35 8d 01 00 00 lea 0x18d(%rip),%rsi # 704 <_IO_stdin_used+0x4>
577: e8 c4 ff ff ff callq 540 <__printf_chk@plt>
57c: 31 c0 xor %eax,%eax
57e: 48 83 c4 08 add $0x8,%rsp
582: c3 retq
583: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
58a: 00 00 00
58d: 0f 1f 00 nopl (%rax)
我们可以看到编译的汇编代码,变量 ra 直接赋值为 0x3333,从而省略了中间赋值过程:
C++
ra = 0x1111;
ra = 0x2222;
ra = 0x3333;
在初始化某些硬件平台时,我们需要按照芯片手册对寄存器依次连续写入一系列的指令,上述程序中假如 ra 为一个寄存器变量,则依次为寄存器按照顺序写入特定的值来操作硬件。如果不添加 volatile 关键字,某些编译器会对上述代码进行优化,直接会省略中间的写入指令。实际在硬件在初始化中不能省略中间的指令,此时编译器的优化反而造成错误,此时我们用 volatile 修饰变量 ra,可以阻止编译器对指令顺序进行优化。
C
0000000000000560 <main>:
560: 48 83 ec 18 sub $0x18,%rsp
564: 48 8d 35 b9 01 00 00 lea 0x1b9(%rip),%rsi # 724 <_IO_stdin_used+0x4>
56b: bf 01 00 00 00 mov $0x1,%edi
570: c7 44 24 0c 00 00 00 movl $0x0,0xc(%rsp)
577: 00
578: c7 44 24 0c 11 11 00 movl $0x1111,0xc(%rsp)
57f: 00
580: c7 44 24 0c 22 22 00 movl $0x2222,0xc(%rsp)
587: 00
588: c7 44 24 0c 33 33 00 movl $0x3333,0xc(%rsp)
58f: 00
590: 8b 44 24 0c mov 0xc(%rsp),%eax
594: 31 c0 xor %eax,%eax
596: 8b 54 24 0c mov 0xc(%rsp),%edx
59a: e8 a1 ff ff ff callq 540 <__printf_chk@plt>
59f: 31 c0 xor %eax,%eax
5a1: 48 83 c4 18 add $0x18,%rsp
5a5: c3 retq
5a6: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
5ad: 00 00 00
3.volatile 的应用场景:
在实际场景中除了操纵硬件需要用到 volatile 以外,更多的可能是多线程并发访问共享变量时,一个线程改变了变量的值,怎样让改变后的值对其它线程可见,此时我们就需要使用 volatile 进行修饰。一般说来,volatile 用在如下的几个地方:
阅读量:2017
点赞量:0
收藏量:0