Deux objects différents avec une durée de stockage automatique peuvent-ils être comparés de manière équivalente?

En particulier, est-il permis que les adresses de deux variables automatiques de différentes fonctions se comparent de la manière suivante:

sink.c

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

principal 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); } 

Je m’attendrais à ce que cette impression not equal puisque f1 et f2 sont des objects distincts. Avec gcc, je n’obtiens not equal , mais avec ma version locale de clang 3.8 1 , l’impression est equal lorsque compilé sous la forme clang -O1 sink.c main.c 2 .

Déassembly make et 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 

… nous voyons que make ne semble jamais créer l’object Foo f2 , il appelle simplement sink avec les rdi et rsi existants (les parameters l et r , respectivement). Celles-ci sont passées par main et sont les mêmes: le premier, rdi , est le pointeur caché vers l’emplacement où placer la valeur de retour, et le second est &f1 , nous nous attendons donc à ce qu’elles soient identiques.


1 J’ai vérifié les versions jusqu’à 7.0 et le comportement est à peu près le même.

2 Cela se produit pour -O1 , -O2 et -O3 , mais pas -O0 qui -O0 not equal place.

La partie standard C11 6.5.9 / 6 dit:

Deux pointeurs se comparent égaux si et seulement si les deux pointeurs sont nuls, les deux pointeurs pointent sur le même object (y compris un pointeur sur un object et un sous-object au début) ou une fonction, les deux pointeurs pointent sur le dernier élément du même tableau object, ou l’un est un pointeur sur un point situé au-delà de la fin d’un object tableau et l’autre est un pointeur sur le début d’un object tableau différent qui suit immédiatement le premier object tableau de l’espace adresse.

Dans ce code, aucune des conditions énumérées ne tient; &f1 et &f2 sont des pointeurs sur différents objects et l’un n’est pas un sous-object de l’autre.

Les pointeurs ne doivent donc pas être comparés égaux. Le compilateur qui signale que l’ equal est non conforme.


Remarque: Si vous avez des doutes sur la légalité de Foo f1 = make(&f1); , voir cette question . C’est bien et la durée de vie de l’object automatique commence à la { précédente.