Ce n'est pas un comportement indéfini , indépendamment de ce que quiconque, officiel ou non , dit, car il est défini par la norme. p->s
, sauf lorsqu'il est utilisé comme lvalue, donne un pointeur identique à (char *)p + offsetof(struct T, s)
. En particulier, il s'agit d'un char
pointeur valide à l'intérieur de l'objet malloc'd, et il y a 100 adresses successives (ou plus, en fonction des considérations d'alignement) qui le suivent immédiatement, qui sont également valides comme char
objets à l'intérieur de l'objet alloué. Le fait que le pointeur ait été dérivé en utilisant ->
au lieu d'ajouter explicitement le décalage au pointeur renvoyé par malloc
, cast vers char *
, n'est pas pertinent.
Techniquement, p->s[0]
est le seul élément du char
tableau à l'intérieur de la structure, les quelques éléments suivants (par exemple à p->s[1]
travers p->s[3]
) sont probablement des octets de remplissage à l'intérieur de la structure, qui pourraient être corrompus si vous effectuez une affectation à la structure dans son ensemble, mais pas si vous accédez simplement à l'individu les membres et le reste des éléments constituent un espace supplémentaire dans l'objet alloué que vous êtes libre d'utiliser comme vous le souhaitez, tant que vous respectez les exigences d'alignement (et que vous n'avez char
aucune exigence d'alignement).
Si vous craignez que la possibilité de chevauchement avec des octets de remplissage dans la structure puisse d'une manière ou d'une autre invoquer des démons nasaux, vous pouvez éviter cela en remplaçant 1
in [1]
par une valeur qui garantit qu'il n'y a pas de remplissage à la fin de la structure. Un moyen simple mais inutile de faire cela serait de créer une structure avec des membres identiques sauf aucun tableau à la fin, et de l'utiliser s[sizeof struct that_other_struct];
pour le tableau. Ensuite, p->s[i]
est clairement défini comme un élément du tableau dans la structure pour i<sizeof struct that_other_struct
et comme un objet char à une adresse suivant la fin de la structure pour i>=sizeof struct that_other_struct
.
Edit: En fait, dans l'astuce ci-dessus pour obtenir la bonne taille, vous devrez peut-être également mettre une union contenant chaque type simple avant le tableau, pour vous assurer que le tableau lui-même commence par un alignement maximal plutôt qu'au milieu du remplissage d'un autre élément . Encore une fois, je ne crois pas que tout cela soit nécessaire, mais je le propose pour le plus paranoïaque des juristes linguistiques.
Edit 2: Le chevauchement avec les octets de remplissage n'est certainement pas un problème, en raison d'une autre partie de la norme. C exige que si deux structures s'accordent dans une sous-séquence initiale de leurs éléments, les éléments initiaux communs sont accessibles via un pointeur vers l'un ou l'autre type. En conséquence, si une structure identique à struct T
mais avec un tableau final plus grand était déclarée, l'élément s[0]
devrait coïncider avec l'élément s[0]
dans struct T
, et la présence de ces éléments supplémentaires ne pourrait pas affecter ou être affectée par l'accès aux éléments communs de la structure plus grande en utilisant un pointeur vers struct T
.