使用Clang,以下内容:
#include <stdio.h>
int main(void)
{ double const x = 1.234;
double *p = (double *) &x;
/* Same with double *p = &x; but with a mere warning from clang
Clang++ does raise an error in this case.
*/
*p = 5.678;
printf("*p = %f\n", *p);
printf(" x = %f\n", x);
if (&x == p) {
printf("&x = %p\n", &x);
printf(" p = %p\n", p);
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
给出输出:
* p = 5.678000
x = 1.234000
&x = 00000080288FFEA8
p = 00000080288FFEA8
编译器究竟如何做到这一点?编译器如何成功编译并避免出现以下输出:
* p = 5.678000
x = 5.678000
&x = 00000080288FFEA8
p = 00000080288FFEA8
修改对象的行为,该行为最初是const通过强制类型转换将const未定义的类型删除。
编译器是否会警告您有关未定义的行为,取决于编译器。完全笼统地做到这一点是不可能的。
优化编译器将基于您的程序不包含未定义行为的事实做出假设。铛输出与它保持一致代替1.234了x在printf通话; 这是合法的,因为x不允许更改。
Bathsheba假设编译器可能会将硬编码的值传递给printf。我以为我要查看生成的程序集,看看是否可以验证假设。
我对所讨论的代码进行了一些小的修改:将doubles 更改为s以便int于理解我在程序集中看到的内容,并且还添加了另一个print语句,将这些值加在一起。
编译与 clang -std=c11 -g -O2
#include <stdio.h>
int main(void)
{ int const x = 1;
int *p = (int *) &x;
*p = 2;
printf("*p = %d\n", *p);
printf(" x = %d\n", x);
printf(" x + p = %d\n", x + *p);
if (&x == p) {
printf("&x = %p\n", (void *)&x);
printf(" p = %p\n", (void *)p);
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
反汇编的代码(仅是主要部分):
0000000000400510 <main>:
400510: 53 push %rbx
400511: 48 83 ec 10 sub $0x10,%rsp
400515: c7 44 24 0c 02 00 00 movl $0x2,0xc(%rsp)
40051c: 00
40051d: bf 10 06 40 00 mov $0x400610,%edi
400522: be 02 00 00 00 mov $0x2,%esi <----- hard-coded 2 passed in
400527: 31 c0 xor %eax,%eax
400529: e8 c2 fe ff ff callq 4003f0 <printf@plt>
40052e: bf 19 06 40 00 mov $0x400619,%edi
400533: be 01 00 00 00 mov $0x1,%esi <----- hard-coded 1 passed in
400538: 31 c0 xor %eax,%eax
40053a: e8 b1 fe ff ff callq 4003f0 <printf@plt>
40053f: bf 22 06 40 00 mov $0x400622,%edi
400544: be 03 00 00 00 mov $0x3,%esi <----- hard-coded 3 passed in (2+1)
400549: 31 c0 xor %eax,%eax
40054b: e8 a0 fe ff ff callq 4003f0 <printf@plt>
400550: 48 8d 5c 24 0c lea 0xc(%rsp),%rbx
400555: bf 2f 06 40 00 mov $0x40062f,%edi
40055a: 31 c0 xor %eax,%eax
40055c: 48 89 de mov %rbx,%rsi
40055f: e8 8c fe ff ff callq 4003f0 <printf@plt>
400564: bf 38 06 40 00 mov $0x400638,%edi
400569: 31 c0 xor %eax,%eax
40056b: 48 89 de mov %rbx,%rsi
40056e: e8 7d fe ff ff callq 4003f0 <printf@plt>
400573: 31 c0 xor %eax,%eax
400575: 48 83 c4 10 add $0x10,%rsp
400579: 5b pop %rbx
40057a: c3 retq
40057b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
Run Code Online (Sandbox Code Playgroud)
实际上,编译器正在传递硬编码的值。