这个问题考虑了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程序集,用于修改外部变量
ExtGlobal++;
0139145E mov ax,word ptr ds:[01398130h]
01391464 add ax,1
01391468 mov word ptr ds:[01398130h],ax
从上面的程序集中,while循环中对变量“ExtGlobal”的每次访问都从相应的地址中读取值。如果我向外部变量添加volatile,则生成相同的汇编代码。两个不同线程中的易失性使用和两个不同函数中的外部变量使用是相同的。
答案 0 :(得分:5)
询问extern
和volatile
就像询问花生和大猩猩一样。他们完全不相关。
extern
只是用来告诉编译器,“嘿,不要指望在这个C文件中找到这个符号的定义。让链接器在最后修复它。”
volatile
基本上告诉编译器,“永远不要相信这个变量的值。即使你只是将一个值从寄存器存储到该内存位置,也不要重复使用寄存器中的值 - 确保从内存中重新读取它。“
如果要查看volatile
导致生成不同的代码,请从变量中写入一系列读/写。
例如,使用gcc -O1 -c
,
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
的值,而总是从内存中重新加载它。