Ce n'est pas un comportement indéfini sans tenir compte de ce qui se passe, officiel ou non dit, parce qu'il est défini par la norme. p->s
sauf lorsqu'il est utilisé en tant que valeur l, est évalué comme un pointeur identique à (char *)p + offsetof(struct T, s)
. En particulier, c'est un char
à l'intérieur de l'objet malloqué, et il y a 100 (ou plus, en fonction de considérations d'alignement) adresses successives qui le suivent immédiatement et qui sont également valides en tant que char
à l'intérieur de l'objet alloué. Le fait que le pointeur ait été dérivé par l'utilisation de ->
au lieu d'ajouter explicitement le décalage au pointeur retourné par malloc
, pour char *
n'est pas pertinent.
Techniquement, p->s[0]
est l'élément unique de la char
à l'intérieur de la structure, les quelques éléments suivants (par ex. p->s[1]
par le biais de 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 à des membres individuels, et le reste des éléments est un espace supplémentaire dans l'objet alloué que vous êtes libre d'utiliser comme vous le souhaitez, tant que vous respectez les exigences en matière d'alignement (et char
n'a pas d'exigences en matière d'alignement).
Si vous craignez que l'éventualité d'un 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 la balise 1
sur [1]
avec une valeur qui garantit qu'il n'y a pas de remplissage à la fin de la structure. Une façon simple mais inutile de le faire serait de créer une structure avec des membres identiques, mais sans tableau à la fin, et d'utiliser la fonction 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 struct pour i<sizeof struct that_other_struct
et comme un objet char à une adresse suivant la fin du struct pour i>=sizeof struct that_other_struct
.
Editar: En fait, dans l'astuce ci-dessus pour obtenir la bonne taille, vous pourriez aussi avoir besoin de mettre une union contenant chaque type simple avant le tableau, pour s'assurer que le tableau lui-même commence avec un alignement maximal plutôt qu'au milieu du padding d'un autre élément. Encore une fois, je ne crois pas que tout cela soit nécessaire, mais je le propose aux plus paranoïaques des avocats du langage.
Edit 2 : Le chevauchement avec les octets de remplissage n'est absolument pas un problème, en raison d'une autre partie de la norme. Le langage C exige que si deux structures se rejoignent dans une sous-séquence initiale de leurs éléments, les éléments initiaux communs peuvent être accédés par un pointeur sur l'un ou l'autre type. Par conséquent, si une structure identique à struct T
mais avec un tableau final plus grand ont été déclarés, l'élément s[0]
devrait coïncider avec l'élément s[0]
sur struct T
et la présence de ces éléments supplémentaires ne pouvait pas affecter ou être affectée par l'accès à des éléments communs de la structure plus grande en utilisant un pointeur à struct T
.