extern和volatile之间的区别

这个问题考虑了volatile和extern变量之间的区别以及编译器优化。

一个外部变量在主文件中定义,并在另一个源文件中使用,如下所示:

ExternTest.cpp:

short ExtGlobal; void Fun(); int _tmain(int argc, _TCHAR* argv[]) { ExtGlobal=1000; while (ExtGlobal < 2000) { Fun(); } return 0; } 

Source1.cpp:

 extern short ExtGlobal; void Fun() { ExtGlobal++; } 

在vs2012中为此生成的程序集如下:

用于访问外部变量的ExternTest.cpp程序集

 ExtGlobal=1000; 013913EE mov eax,3E8h 013913F3 mov word ptr ds:[01398130h],ax while (ExtGlobal < 2000) 013913F9 movsx eax,word ptr ds:[1398130h] 01391400 cmp eax,7D0h 01391405 jge wmain+3Eh (0139140Eh) 

Source.cpp程序集用于修改extern变量

 ExtGlobal++; 0139145E mov ax,word ptr ds:[01398130h] 01391464 add ax,1 01391468 mov word ptr ds:[01398130h],ax 

从上面的程序集中,while循环中对变量“ExtGlobal”的每次访问都从相应的地址中读取值。 如果我将volatile添加到外部变量,则生成相同的汇编代码。 两个不同线程中的易失性使用和两个不同function中的外部变量使用是相同的。

询问externvolatile就像询问花生和大猩猩。 他们完全没有关系。

extern用于告诉编译器,“嘿,不要指望在这个C文件中找到这个符号的定义。让链接器在最后修复它。”

volatile本质上告诉编译器,“永远不要相信这个变量的值。即使你只是将一个值从寄存器存储到该内存位置,也不要重复使用寄存器中的值 – 确保重新读取它记忆。”

如果要查看volatile会导致生成不同的代码,请从变量中写入一系列读/写。

例如,使用gcc -O1 -c在cygwin中编译此代码,

 int i; void foo() { i = 4; i += 2; i -= 1; } 

生成以下程序集:

 _foo proc near mov dword ptr ds:_i, 5 retn _foo endp 

请注意,编译器知道结果是什么,所以它只是继续并优化它。

现在,将volatile添加到int i生成以下内容:

 public _foo _foo proc near mov dword ptr ds:_i, 4 mov eax, dword ptr ds:_i add eax, 2 mov dword ptr ds:_i, eax mov eax, dword ptr ds:_i sub eax, 1 mov dword ptr ds:_i, eax retn _foo endp 

编译器永远不会信任i的值,并始终从内存重新加载它。