Extension de structure en C

Aug 21 2020

Supposons qu'il existe 2 structures définies comme:

typedef struct {
   T x;
   T y;
} A;

typedef struct {
   A a;
   T z;
} B;

Puis-je traiter un pointeur vers la structure B comme un pointeur vers la structure A?

En pratique, est-ce fiable / standard / portable / invariant au compilateur:

B b = {{1,2},3};
A * a = &b;

print(a->x);
print(a->y);

Réponses

3 Lundin Aug 21 2020 at 08:19

C17 6.7.2.1 indique ceci (c'est moi qui souligne):

Dans un objet de structure, les membres de champ non binaire et les unités dans lesquelles résident les champs binaires ont des adresses qui augmentent dans l'ordre dans lequel ils sont déclarés. Un pointeur vers un objet de structure, convenablement converti, pointe vers son membre initial (ou si ce membre est un champ de bits, puis vers l'unité dans laquelle il réside), et vice versa .

Cela signifie que vous devez «convertir convenablement» le pointeur de l' B bobjet dans le type de son premier membre. Cette conversion ne se produit pas implicitement, vous devez le faire au moyen d'un cast explicite:

A * a = (A*)&b;

Cela est bien défini et sûr, conformément à la partie citée ci-dessus.

De même, le compilateur n'est pas autorisé à supposer qu'un pointeur vers Aet un pointeur vers Bne pas d'alias. La règle de type efficace 6.5.7 ("aliasing strict") donne une exception dans ce cas:

Un objet doit avoir sa valeur stockée accessible uniquement par une expression lvalue qui a l'un des types suivants:
...

  • un type d'agrégat ou d'union qui comprend l'un des types susmentionnés parmi ses membres

Par exemple, pendant l'optimisation, un compilateur appelant la fonction void func (B* b)n'est pas autorisé à supposer qu'une variable de lignage externe extern A a;définie dans une autre unité de traduction n'a pas été modifiée par la fonction.