具有自动存储持续时间的两个不同对象在地址比较下是否相等?

特别是,允许​​不同函数中两个自动变量的地址比较如下:

sink.c

#include  #include  void sink(void *l, void *r) { puts(l == r ? "equal" : "not equal"); exit(0); } 

main.c中

 typedef struct { char x[32]; } Foo; void sink(void *l, void *r); Foo make(void *p) { Foo f2; sink(&f2, p); return f2; } int main() { Foo f1 = make(&f1); } 

我希望这打印not equal因为f1f2是不同的对象。 使用gcc我得到的not equal ,但是使用我的本地版本的clang 3.8 1 ,它打印equal ,当编译为clang -O1 sink.c main.c 2

拆卸makemain ……

 0000000000400570 : 400570: 53 push rbx 400571: 48 89 fb mov rbx,rdi 400574: e8 d7 ff ff ff call 400550  400579: 48 89 d8 mov rax,rbx 40057c: 5b pop rbx 40057d: c3 ret 40057e: 66 90 xchg ax,ax 0000000000400580 : 400580: 48 83 ec 28 sub rsp,0x28 400584: 48 8d 7c 24 08 lea rdi,[rsp+0x8] 400589: 48 89 fe mov rsi,rdi 40058c: e8 df ff ff ff call 400570  400591: 31 c0 xor eax,eax 400593: 48 83 c4 28 add rsp,0x28 400597: c3 ret 

…我们看到make似乎永远不会创建Foo f2对象,它只是用现有的rdirsi (分别是lr参数)调用sink 。 这些是由main传递的并且是相同的:第一个, rdi是指向放置返回值的位置的隐藏指针,第二个是&f1 ,所以我们希望它们是相同的。


1我检查的版本高达7.0,行为大致相同。

2它发生在-O1-O2-O3 ,但不是-O0 ,而是打印not equal

C11标准6.5.9 / 6部分说:

两个指针比较相等,当且仅当两个都是空指针时,两者都是指向同一对象的指针(包括指向对象的指针和在其开头的子对象)或函数,两者都是指向同一数组的最后一个元素之后的指针对象,或者一个是指向一个数组对象末尾的指针,另一个是指向不同数组对象的开头的指针,该数组对象恰好跟随地址空间中的第一个数组对象。

在此代码中,没有列出的条件成立; &f1&f2是指向不同对象的指针,一个不是另一个对象的子对象。

所以指针不能相等。 报告equal的编译器是不符合的。


注意:如果有人对Foo f1 = make(&f1);的合法性有疑问Foo f1 = make(&f1); , 看到这个问题 。 它很好,自动对象的生命周期从前面的{开始。