В частности, разрешено ли сравнивать адреса двух автоматических переменных в разных функциях следующим образом:
sink.c
#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
.