extern和volatile之间的区别

use*_*861 1 c

这个问题涉及volatile和extern变量之间的区别以及编译器优化.

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

ExternTest.cpp:

short ExtGlobal;
void Fun();

int _tmain(int argc, _TCHAR* argv[])
{

    ExtGlobal=1000;
    while (ExtGlobal < 2000)
    {
        Fun();
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

Source1.cpp:

extern short ExtGlobal;

void Fun()
{
    ExtGlobal++;
}
Run Code Online (Sandbox Code Playgroud)

在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) 
Run Code Online (Sandbox Code Playgroud)

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

ExtGlobal++;
0139145E  mov         ax,word ptr ds:[01398130h]  
01391464  add         ax,1  
01391468  mov         word ptr ds:[01398130h],ax  
Run Code Online (Sandbox Code Playgroud)

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

Jon*_*art 5

询问extern并且volatile就像询问花生和大猩猩一样.他们完全没有关系.

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

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

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

例如,编译Cygwin中的代码,用gcc -O1 -c,

int i;

void foo() {
    i = 4;

    i += 2;

    i -= 1;
}
Run Code Online (Sandbox Code Playgroud)

生成以下程序集:

_foo proc near
mov     dword ptr ds:_i, 5
retn
_foo endp
Run Code Online (Sandbox Code Playgroud)

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

现在,添加volatileint 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
Run Code Online (Sandbox Code Playgroud)

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