这个问题涉及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,则生成相同的汇编代码.两个不同线程中的易失性使用和两个不同功能中的外部变量使用是相同的.
询问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)
请注意,编译器知道结果是什么,所以它只是继续并优化它.
现在,添加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
Run Code Online (Sandbox Code Playgroud)
编译器永远不会信任它的值i,并始终从内存中重新加载它.
| 归档时间: |
|
| 查看次数: |
1078 次 |
| 最近记录: |