C语言 volatile关键字

81 阅读1分钟

一段最简单的代码

int a = 10;
int foo()
{
    int b = a;
    // do something for delay
    return b - a;
}

编译命令:gcc -c -O3 a.c -o a.o (-O3参数开启优化), 反汇编的结果是这样的

0000000000000000 :
0:   31 c0                 xor    eax,eax
2:   c3                      ret

直接返回一个0(返回值在eax中)。如果是仅仅是上面的代码,直接返回0自然没有问题,但如果是多线程的环境中,或者是在中断上下文中,a有可能在别的地方被随时更改,那么b-a就不定是0了,直接返回0的结果就不对了。(这里用锁来保护a是不行的,因为锁是在运行时生效的,而代码是在优化编译时进行的)。

将a的定义改成这样的,其他不变

volatile int a = 10;

同样的命令进行编译,反汇编的结果是这样的

0000000000000000 :
0:   8b 05 00 00 00 00       mov    eax,DWORD PTR [rip+0x0]        # 6 <foo+0x6>
6:   8b 15 00 00 00 00       mov    edx,DWORD PTR [rip+0x0]        # c <foo+0xc>
c:   29 d0                   sub    eax,edx
e:   c3                      ret

解释一下这段代码就是:首先将a的值赋给eax,再将a的值赋给edx,最后返回eax-edx,即使在两次赋值的中间过程中a的值发生了变化,结果都是对的。

所以volatile关键字的作用就是告诉编译器,该变量是随时有可能变化的,不要对其进行优化,每次用到的时候都要从内存中读取。