Considérez la structure suivante:
struct s {
int a, b;
};
Typiquement 1 , cette structure aura la taille 8 et l'alignement 4.
Et si nous créons deux struct s
objets (plus précisément, nous écrivons dans le stockage alloué deux de ces objets), le deuxième objet chevauchant le premier?
char *storage = malloc(3 * sizeof(struct s));
struct s *o1 = (struct s *)storage; // offset 0
struct s *o2 = (struct s *)(storage + alignof(struct s)); // offset 4
// now, o2 points half way into o1
*o1 = (struct s){1, 2};
*o2 = (struct s){3, 4};
printf("o2.a=%d\n", o2->a);
printf("o2.b=%d\n", o2->b);
printf("o1.a=%d\n", o1->a);
printf("o1.b=%d\n", o1->b);
Y a-t-il quelque chose sur ce comportement indéfini du programme? Si oui, où devient-il indéfini? Si ce n'est pas UB, est-il garanti d'imprimer toujours ce qui suit:
o2.a=3
o2.b=4
o1.a=1
o1.b=3
En particulier, je veux savoir ce qui arrive à l'objet pointé par o1
quand o2
, qui le chevauche, est écrit. Est-il toujours autorisé à accéder à la partie non nettoyée ( o1->a
)? L'accès à la partie encombrée est-il o1->b
simplement identique à l'accès o2->a
?
Comment le type efficace s'applique-t-il ici? Les règles sont suffisamment claires lorsque vous parlez d'objets qui ne se chevauchent pas et de pointeurs pointant vers le même emplacement que le dernier magasin, mais lorsque vous commencez à parler du type effectif de parties d'objets ou d'objets qui se chevauchent, c'est moins clair.
Est-ce que quelque chose changerait si la deuxième écriture était d'un type différent? Si les membres se disaient int
et short
plutôt que deux int
s?
Voici un coup de foudre si vous voulez y jouer avec.
1 Cette réponse s'applique aux plates-formes où ce n'est pas le cas également: par exemple, certaines pourraient avoir la taille 4 et l'alignement 2. Sur une plate-forme où la taille et l'alignement étaient les mêmes, cette question ne s'appliquerait pas car des objets alignés et se chevauchant être impossible, mais je ne suis pas sûr qu'il existe une telle plate-forme.