特别是允许不同函数中的两个自动变量的地址相等,如下所示:
下沉
#include <stdio.h>
#include <stdlib.h>
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 <make>:
400570: 53 push rbx
400571: 48 89 fb mov rbx,rdi
400574: e8 d7 ff ff ff call 400550 <sink>
400579: 48 89 d8 mov rax,rbx
40057c: 5b pop rbx
40057d: c3 ret
40057e: 66 90 xchg ax,ax
0000000000400580 <main>:
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 <make>
400591: 31 c0 xor eax,eax
400593: 48 83 c4 28 add rsp,0x28
400597: c3 ret
...我们看到make
似乎根本没有创建Foo f2
对象,它只是sink
使用现有的rdi
和rsi
(分别为l
和r
参数)进行调用。它们的传递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);
,请参阅此问题。很好,自动对象的生存期从前一个开始{
。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句