具有自动存储持续时间的两个不同对象在地址比较下是否相等?
特别是,允许不同函数中两个自动变量的地址比较如下:
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
因为f1
和f2
是不同的对象。 使用gcc我得到的not equal
,但是使用我的本地版本的clang 3.8 1 ,它打印equal
,当编译为clang -O1 sink.c main.c
2 。
拆卸make
和main
……
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
对象,它只是用现有的rdi
和rsi
(分别是l
和r
参数)调用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);
, 看到这个问题 。 它很好,自动对象的生命周期从前面的{
开始。