Es ist kein undefiniertes Verhalten , unabhängig davon, was jemand, offiziell oder anderweitig , sagt, da es durch den Standard definiert ist. p->s
, außer wenn es als l-Wert verwendet wird, wird zu einem Zeiger ausgewertet, der mit identisch ist (char *)p + offsetof(struct T, s)
. Dies ist insbesondere ein gültiger char
Zeiger innerhalb des malloc'd-Objekts, und unmittelbar darauf folgen 100 (oder mehr, abhängig von Ausrichtungsüberlegungen) aufeinanderfolgende Adressen, die auch als char
Objekte innerhalb des zugewiesenen Objekts gültig sind . Die Tatsache, dass der Zeiger durch Verwenden ->
von abgeleitet wurde, anstatt den Versatz explizit zu dem Zeiger hinzuzufügen, der von malloc
, in den umgewandelt wurde char *
, zurückgegeben wird, ist irrelevant.
Technisch gesehen p->s[0]
ist das einzelne Element des char
Arrays innerhalb der Struktur, die nächsten paar Elemente (z. B. p->s[1]
bis p->s[3]
) sind wahrscheinlich Auffüllbytes innerhalb der Struktur, die beschädigt werden können, wenn Sie die Zuordnung zur Struktur als Ganzes durchführen, aber nicht, wenn Sie nur auf einzelne zugreifen Mitglieder und der Rest der Elemente sind zusätzlicher Speicherplatz im zugewiesenen Objekt, den Sie nach Belieben verwenden können, solange Sie die Ausrichtungsanforderungen erfüllen (und char
keine Ausrichtungsanforderungen haben).
Wenn Sie befürchten, dass die Möglichkeit einer Überlappung mit Auffüllbytes in der Struktur Nasen-Dämonen hervorrufen könnte, können Sie dies vermeiden, indem Sie das 1
In [1]
durch einen Wert ersetzen, der sicherstellt, dass am Ende der Struktur kein Auffüllen erfolgt. Eine einfache, aber verschwenderische Möglichkeit, dies zu tun, besteht darin, eine Struktur mit identischen Elementen außer keinem Array am Ende zu erstellen und s[sizeof struct that_other_struct];
für das Array zu verwenden. Dann p->s[i]
ist klar definiert als ein Element des Arrays in der Struktur für i<sizeof struct that_other_struct
und als ein char-Objekt an einer Adresse nach dem Ende der Struktur für i>=sizeof struct that_other_struct
.
Bearbeiten: Bei dem obigen Trick, um die richtige Größe zu erhalten, müssen Sie möglicherweise auch eine Vereinigung mit jedem einfachen Typ vor das Array setzen, um sicherzustellen, dass das Array selbst mit maximaler Ausrichtung beginnt und nicht in der Mitte des Auffüllens eines anderen Elements . Auch hier glaube ich nicht, dass dies notwendig ist, aber ich biete es den paranoidesten Sprachanwälten da draußen an.
Bearbeiten 2: Die Überlappung mit Füllbytes ist aufgrund eines anderen Teils des Standards definitiv kein Problem. C erfordert, dass, wenn zwei Strukturen in einer anfänglichen Teilsequenz ihrer Elemente übereinstimmen, auf die gemeinsamen Anfangselemente über einen Zeiger auf einen der beiden Typen zugegriffen werden kann. Wenn daher eine Struktur struct T
deklariert würde, die mit einem größeren endgültigen Array identisch ist, jedoch mit einem größeren endgültigen Array, s[0]
müsste das Element mit dem Element s[0]
in übereinstimmen struct T
, und das Vorhandensein dieser zusätzlichen Elemente könnte den Zugriff auf gemeinsame Elemente der größeren Struktur nicht beeinflussen oder durch diesen beeinflusst werden mit einem Zeiger auf struct T
.