Non è un comportamento indefinito , a prescindere da ciò che qualcuno, ufficiale o meno , dice, perché è definito dallo standard. p->s
, tranne quando usato come lvalue, restituisce un puntatore identico a (char *)p + offsetof(struct T, s)
. In particolare, questo è un char
puntatore valido all'interno dell'oggetto malloc'd, e ci sono 100 (o più, a seconda delle considerazioni sull'allineamento) successivi indirizzi immediatamente successivi che sono validi anche come char
oggetti all'interno dell'oggetto allocato. Il fatto che il puntatore sia stato derivato usando ->
invece di aggiungere esplicitamente l'offset al puntatore restituito da malloc
, cast to char *
, è irrilevante.
Tecnicamente, p->s[0]
è il singolo elemento char
dell'array all'interno della struttura, i pochi elementi successivi (ad esempio p->s[1]
attraverso p->s[3]
) sono probabilmente byte di riempimento all'interno della struttura, che potrebbero essere corrotti se esegui l'assegnazione alla struttura nel suo insieme ma non se accedi semplicemente a singoli membri, e il resto degli elementi è spazio aggiuntivo nell'oggetto assegnato che sei libero di usare come preferisci, a condizione che tu obbedisca ai requisiti di allineamento (e char
non abbia requisiti di allineamento).
Se sei preoccupato che la possibilità di sovrapporsi con padding byte nella struttura possa in qualche modo richiamare i demoni nasali, potresti evitarlo sostituendo 1
in [1]
con un valore che assicuri che non ci sia riempimento alla fine della struttura. Un modo semplice ma dispendioso per farlo sarebbe creare una struttura con membri identici tranne nessun array alla fine, e usarla s[sizeof struct that_other_struct];
per l'array. Quindi, p->s[i]
è chiaramente definito come un elemento dell'array nella struct for i<sizeof struct that_other_struct
e come un oggetto char in un indirizzo che segue la fine della struct for i>=sizeof struct that_other_struct
.
Modifica: in realtà, nel trucco sopra per ottenere la dimensione giusta, potresti anche dover mettere un'unione contenente ogni tipo semplice prima dell'array, per assicurarti che l'array stesso inizi con l'allineamento massimo piuttosto che nel mezzo del riempimento di qualche altro elemento . Ancora una volta, non credo che tutto ciò sia necessario, ma lo offro al più paranoico degli avvocati linguistici là fuori.
Modifica 2: la sovrapposizione con i byte di riempimento non è sicuramente un problema, a causa di un'altra parte dello standard. C richiede che se due strutture concordano in una sottosequenza iniziale dei loro elementi, è possibile accedere agli elementi iniziali comuni tramite un puntatore a entrambi i tipi. Di conseguenza, se struct T
fosse dichiarata una struttura identica a ma con un array finale più grande, l'elemento s[0]
dovrebbe coincidere con l'elemento s[0]
in struct T
, e la presenza di questi elementi aggiuntivi non potrebbe influenzare o essere influenzata dall'accesso agli elementi comuni della struttura più grande utilizzando un puntatore a struct T
.