Dar*_*bik 9 c++ g++ volatile language-lawyer
考虑以下代码:
struct A{
volatile int x;
A() : x(12){
}
};
A foo(){
A ret;
//Do stuff
return ret;
}
int main()
{
A a;
a.x = 13;
a = foo();
}
Run Code Online (Sandbox Code Playgroud)
使用g++ -std=c++14 -pedantic -O3我得到这个程序集:
foo():
movl $12, %eax
ret
main:
xorl %eax, %eax
ret
Run Code Online (Sandbox Code Playgroud)
根据我的估计,变量x应写入至少三次(可能是四次),但它甚至不写一次(函数foo甚至不被调用!)
更糟糕的是,当您向其添加inline关键字时,foo结果如下:
main:
xorl %eax, %eax
ret
Run Code Online (Sandbox Code Playgroud)
我认为volatile意味着即使编译器看不到读/写的点,每次读或写都必须发生.
这里发生了什么?
更新:
A a;像这样把外部主要的声明:
A a;
int main()
{
a.x = 13;
a = foo();
}
Run Code Online (Sandbox Code Playgroud)
生成此代码:
foo():
movl $12, %eax
ret
main:
movl $13, a(%rip)
xorl %eax, %eax
movl $12, a(%rip)
ret
movl $12, a(%rip)
ret
a:
.zero 4
Run Code Online (Sandbox Code Playgroud)
这更接近你所期望的......我甚至更加困惑
Visual C++ 2015 does not optimize away the assignments:
A a;
mov dword ptr [rsp+8],0Ch <-- write 1
a.x = 13;
mov dword ptr [a],0Dh <-- write2
a = foo();
mov dword ptr [a],0Ch <-- write3
mov eax,dword ptr [rsp+8]
mov dword ptr [rsp+8],eax
mov eax,dword ptr [rsp+8]
mov dword ptr [rsp+8],eax
}
xor eax,eax
ret
Run Code Online (Sandbox Code Playgroud)
/O2(最大化速度)和 /Ox(完全优化)也会发生同样的情况。
gcc 3.4.4 也使用 -O2 和 -O3 保留易失性写入
_main:
pushl %ebp
movl $16, %eax
movl %esp, %ebp
subl $8, %esp
andl $-16, %esp
call __alloca
call ___main
movl $12, -4(%ebp) <-- write1
xorl %eax, %eax
movl $13, -4(%ebp) <-- write2
movl $12, -8(%ebp) <-- write3
leave
ret
Run Code Online (Sandbox Code Playgroud)
使用这两个编译器,如果我删除 volatile 关键字,main() 基本上会变成空。
我想说的是,在这种情况下,编译器过于激进(并且错误地恕我直言)决定,由于未使用“a”,因此不需要对它进行操作,并且忽略了易失性成员。使 'a' 本身变得易失性可以让你得到你想要的东西,但由于我没有可以重现这一点的编译器,我不能肯定地说。
最后(虽然这确实是微软特有的),https://msdn.microsoft.com/en-us/library/12a04hfd.aspx说:
如果结构体成员被标记为易失性,则易失性将传播到整个结构。
这也表明您所看到的行为是编译器问题。
最后,如果将“a”设置为全局变量,那么编译器不太愿意将其视为未使用并删除它,这在某种程度上是可以理解的。全局变量默认是extern的,所以仅仅看main函数并不能说全局'a'没有被使用。其他一些编译单元(.cpp 文件)可能正在使用它。
| 归档时间: |
|
| 查看次数: |
575 次 |
| 最近记录: |