代码:
#define OPPOSITE(c) (*((typeof(x) *)&(x)))
int foo(volatile int x)
{
OPPOSITE(x) = OPPOSITE(x) + OPPOSITE(x);
return x;
}
int bar(volatile int x)
{
OPPOSITE(x) = OPPOSITE(x) + OPPOSITE(x);
return x;
}
结果(-Os):
foo:
mov DWORD PTR [rsp-4], edi
mov eax, DWORD PTR [rsp-4]
mov edx, DWORD PTR [rsp-4]
add eax, edx
mov DWORD PTR [rsp-4], eax
mov eax, DWORD PTR [rsp-4]
ret
bar:
mov DWORD PTR [rsp-4], edi
mov eax, DWORD PTR [rsp-4]
add eax, eax
ret
或者ARM gcc。(-O3
)
foo:
sub sp, sp, #8
str r0, [sp, #4]
ldr r3, [sp, #4]
ldr r2, [sp, #4]
add r3, r3, r2
str r3, [sp, #4]
ldr r0, [sp, #4]
add sp, sp, #8
bx lr
bar:
sub sp, sp, #8
str r0, [sp, #4]
ldr r0, [sp, #4]
lsl r0, r0, #1
add sp, sp, #8
bx lr
#define OPPOSITE(c) (c)
相同的代码生成 https://godbolt.org/z/MWsbT5nan,所以这是GCC的一个错误:不尊重volatile赋值,也不尊重右侧有两个读取的事实。(除非我错过了关于序列点和对易访问volatile对象的多个未排序访问是UB的某些内容?不,使用tmp变量的相同代码生成:https://godbolt.org/z/r4evhT913) - Peter Cordesint foo(volatile int x) { x = x + x; return x; } int bar(volatile int x) { x = x + x; return x; }
。同样的错误。这在C11之后是未定义行为,但在C99中是有明确定义的。 - Lundinbar
具有外部链接,因此在从翻译单元之外调用时,必须有正确的代码。 - Eric Postpischil