これは標準で定義されているため、公式または別の人の発言に関係なく、未定義の動作ではありません。p->s左辺値として使用される場合を除き、と同じポインタに評価されます(char *)p + offsetof(struct T, s)。特に、これはcharmallocされたオブジェクト内の有効なポインターでありchar、割り当てられたオブジェクト内のオブジェクトとしても有効な、それに続く100(またはそれ以上)の連続するアドレスが直後に続きます。ポインタが使用することによって導き出されたという事実->はなく、明示的で返されるポインタにオフセットを追加することmallocにキャストが、char *無関係です。
技術的にp->s[0]は、char構造体内の配列の単一の要素であり、次のいくつかの要素(例:p->s[1]からp->s[3])は、構造体内のバイトにパディングしている可能性があり、構造全体への割り当てを実行すると破損する可能性がありますが、個々にアクセスするだけでは破損しませんメンバー、および残りの要素は、割り当てられたオブジェクトの追加のスペースであり、配置要件に従っている限り(配置要件charがない限り)、自由に使用できます。
構造体のパディングバイトとオーバーラップする可能性が何らかの理由で鼻の悪魔を呼び出すのではないかと心配している場合は、構造体の最後にパディングがないことを保証する値で1in [1]を置き換えることでこれを回避できます。これを行う単純で無駄な方法は、最後に配列がないことを除いて同一のメンバーで構造体を作成s[sizeof struct that_other_struct];し、配列に使用することです。次に、p->s[i]はstruct forの配列の要素として、i<sizeof struct that_other_structおよびstruct for の末尾に続くアドレスのcharオブジェクトとして明確に定義されていi>=sizeof struct that_other_structます。
編集:実際には、適切なサイズを取得するための上記のトリックでは、配列の前にすべての単純型を含む共用体を配置して、配列自体が他の要素のパディングの中央ではなく最大の配置で始まるようにする必要がある場合もあります。 。繰り返しになりますが、これが必要だとは思いませんが、私はそこにいる言語弁護士の最も偏執的な人のために提供しています。
編集2:標準の別の部分により、パディングバイトとの重複は問題にはなりません。Cは、2つの構造体がそれらの要素の最初のサブシーケンスで一致する場合、いずれかの型へのポインターを介して共通の初期要素にアクセスできることを要求します。結果として、同一の構造体であればstruct Tより大きな最終配列が宣言されたと、要素がs[0]要素と一致しなければならないs[0]でstruct T、これらの追加要素の存在は影響しなかったか、より大きな構造体の共通の要素にアクセスすることによって影響を受けることへのポインタを使用しますstruct T。