Considera la seguente struttura:
struct s {
int a, b;
};
Tipicamente 1 , questa struttura avrà dimensione 8 e allineamento 4.
Cosa succede se creiamo due struct s
oggetti (più precisamente, scriviamo nella memoria allocata due di questi oggetti), con il secondo oggetto che si sovrappone al primo?
char *storage = malloc(3 * sizeof(struct s));
struct s *o1 = (struct s *)storage; // offset 0
struct s *o2 = (struct s *)(storage + alignof(struct s)); // offset 4
// now, o2 points half way into o1
*o1 = (struct s){1, 2};
*o2 = (struct s){3, 4};
printf("o2.a=%d\n", o2->a);
printf("o2.b=%d\n", o2->b);
printf("o1.a=%d\n", o1->a);
printf("o1.b=%d\n", o1->b);
C'è qualcosa nel comportamento indefinito di questo programma? In tal caso, dove diventa indefinito? Se non è UB, è garantito stampare sempre quanto segue:
o2.a=3
o2.b=4
o1.a=1
o1.b=3
In particolare, voglio sapere cosa succede all'oggetto indicato da o1
quando o2
, che si sovrappone, viene scritto. È ancora consentito accedere alla parte senza lobo ( o1->a
)? L'accesso alla parte bloccata è o1->b
semplicemente uguale all'accesso o2->a
?
Come si applica il tipo efficace qui? Le regole sono abbastanza chiare quando si parla di oggetti e puntatori non sovrapposti che puntano alla stessa posizione dell'ultimo negozio, ma quando si inizia a parlare del tipo effettivo di porzioni di oggetti o di oggetti sovrapposti, è meno chiaro.
Qualcosa cambierebbe se la seconda scrittura fosse di un tipo diverso? Se i membri fossero stati detti int
e short
non due int
s?
Ecco un godbolt se vuoi giocarci lì.
1 Questa risposta si applica alle piattaforme in cui non è così: ad esempio, alcuni potrebbero avere dimensioni 4 e allineamento 2. Su una piattaforma in cui le dimensioni e l'allineamento erano uguali, questa domanda non si applica poiché gli oggetti allineati e sovrapposti verrebbero essere impossibile, ma non sono sicuro che esista una piattaforma del genere.