Les structures C avec les mêmes types de membres ont-elles la garantie d’avoir la même disposition en mémoire?

Essentiellement, si j’ai

typedef struct { int x; int y; } A; typedef struct { int h; int k; } B; 

et j’ai A a , la norme C garantit-elle que ((B*)&a)->k est identique à ay ?

    Les structures C avec les mêmes types de membres ont-elles la garantie d’avoir la même disposition en mémoire?

    Oui presque. Assez proche pour moi.

    À partir de n1516, section 6.5.2.3, paragraphe 6:

    … si une union contient plusieurs structures partageant une séquence initiale commune …, et si l’object d’union contient actuellement l’une de ces structures, il est permis d’inspecter la partie initiale commune de l’une d’entre elles partout où une déclaration de la type complet de l’union est visible. Deux structures partagent une séquence initiale commune si les membres correspondants ont des types compatibles (et, pour les champs de bits, les mêmes largeurs) pour une séquence d’un ou de plusieurs membres initiaux.

    Cela signifie que si vous avez le code suivant:

     struct a { int x; int y; }; struct b { int h; int k; }; union { struct aa; struct bb; } u; 

    Si vous atsortingbuez à ua , la norme indique que vous pouvez lire les valeurs correspondantes à partir de ub . Il étend les limites de la plausibilité en suggérant que struct a et struct b peuvent avoir une présentation différente, étant donné cette exigence. Un tel système serait pathologique à l’extrême.

    Rappelez-vous que la norme garantit également que:

    • Les structures ne sont jamais des représentations de piège.

    • Les adresses de champs dans une structure augmentent ( ax est toujours avant ay ).

    • Le décalage du premier champ est toujours zéro.

    Cependant, et c’est important!

    Vous avez reformulé la question,

    La norme C garantit-elle que ((B*)&a)->k est identique à y?

    Non! Et il est dit très explicitement qu’ils ne sont pas les mêmes!

     struct a { int x; }; struct b { int x; }; int test(int value) { struct aa; ax = value; return ((struct b *) &a)->x; } 

    Ceci est une violation de crénelage.

    Le portage sur les autres réponses avec un avertissement concernant la section 6.5.2.3. Apparemment, il existe un débat sur le libellé exact de la anywhere that a declaration of the completed type of the union is visible , où au moins GCC ne l’applique pas telle qu’elle a été écrite . Il y a quelques rapports de défauts C WG tangentiels ici et ici avec des commentaires de suivi du comité.

    Récemment, j’ai essayé de savoir comment d’autres compilateurs (notamment GCC 4.8.2, ICC 14 et Clang 3.4) interprètent cela en utilisant le code suivant de la norme:

     // Undefined, result could (realistically) be either -1 or 1 struct t1 { int m; } s1; struct t2 { int m; } s2; int f(struct t1 *p1, struct t2 *p2) { if (p1->m < 0) p2->m = -p2->m; return p1->m; } int g() { union { struct t1 s1; struct t2 s2; } u; u.s1.m = -1; return f(&u.s1,&u.s2); } 

    GCC: -1, clang: -1, ICC: 1 et met en garde sur la violation de pseudonyme

     // Global union declaration, result should be 1 according to a literal reading of 6.5.2.3/6 struct t1 { int m; } s1; struct t2 { int m; } s2; union u { struct t1 s1; struct t2 s2; }; int f(struct t1 *p1, struct t2 *p2) { if (p1->m < 0) p2->m = -p2->m; return p1->m; } int g() { union uu; u.s1.m = -1; return f(&u.s1,&u.s2); } 

    GCC: -1, clang: -1, ICC: 1 mais met en garde contre la violation de crénelage

     // Global union definition, result should be 1 as well. struct t1 { int m; } s1; struct t2 { int m; } s2; union u { struct t1 s1; struct t2 s2; } u; int f(struct t1 *p1, struct t2 *p2) { if (p1->m < 0) p2->m = -p2->m; return p1->m; } int g() { u.s1.m = -1; return f(&u.s1,&u.s2); } 

    GCC: -1, clang: -1, ICC: 1, aucun avertissement

    Bien entendu, sans optimisation ssortingcte des alias, les trois compilateurs renvoient le résultat attendu à chaque fois. Puisque clang et gcc n’ont pas eu de résultats remarquables dans aucun des cas, la seule information réelle provient de l’absence de diagnostic par ICC sur le dernier. Cela correspond également à l’exemple donné par le comité des normes dans le premier rapport sur les défauts mentionné ci-dessus.

    En d’autres termes, cet aspect de C est un véritable champ de mines et vous devrez vous méfier du fait que votre compilateur fait la bonne chose, même si vous suivez les règles à la lettre. Pire encore, il est intuitif qu’une telle paire de structures soit compatible en mémoire.

    Ce type de repliement nécessite spécifiquement un type d’ union . C11 §6.5.2.3 / 6:

    Une garantie spéciale est donnée afin de simplifier l’utilisation des unions: si une union contient plusieurs structures partageant une séquence initiale commune (voir ci-dessous), et si l’object union contient actuellement l’une de ces structures, il est autorisé à inspecter la structure commune. partie initiale de l’un d’entre eux où qu’une déclaration du type complet de l’union soit visible. Deux structures partagent une séquence initiale commune si les membres correspondants ont des types compatibles (et, pour les champs de bits, les mêmes largeurs) pour une séquence d’un ou de plusieurs membres initiaux.

    Cet exemple suit:

    Ce qui suit n’est pas un fragment valide (car le type d’union n’est pas visible dans la fonction f):

     struct t1 { int m; }; struct t2 { int m; }; int f(struct t1 *p1, struct t2 *p2) { if (p1->m < 0) p2->m = -p2->m; return p1->m; } int g() { union { struct t1 s1; struct t2 s2; } u; /* ... */ return f(&u.s1, &u.s2);} } 

    Les exigences semblent être que 1. l’object faisant l’object d’un alias est stocké dans une union et 2. que la définition de ce type d’ union est dans la scope.

    Pour ce que cela vaut, la relation initiale-sous-séquence correspondante en C ++ ne nécessite pas d’ union . Et en général, une telle dépendance à l’ union serait un comportement extrêmement pathologique pour un compilateur. S’il existe une possibilité qu’un type d’union puisse affecter un modèle de mémoire concerete, il est probablement préférable de ne pas l’imaginer.

    Je suppose que l’intention est qu’un vérificateur d’access à la mémoire (pensez à Valgrind sur les stéroïdes) puisse vérifier une erreur d’alias potentielle par rapport à ces règles “ssortingctes”.