Estensione di Struct in C
Supponiamo che ci siano 2 strutture definite come:
typedef struct {
T x;
T y;
} A;
typedef struct {
A a;
T z;
} B;
Posso trattare un puntatore alla struttura B come puntatore alla struttura A?
In pratica è questo affidabile / standard / portatile / invariante del compilatore:
B b = {{1,2},3};
A * a = &b;
print(a->x);
print(a->y);
Risposte
C17 6.7.2.1 afferma questo (enfasi mia):
All'interno di un oggetto struttura, i membri del campo non di bit e le unità in cui risiedono i campi di bit hanno indirizzi che aumentano nell'ordine in cui sono dichiarati. Un puntatore a un oggetto struttura, opportunamente convertito, punta al suo membro iniziale (o se quel membro è un campo di bit, quindi all'unità in cui risiede) e viceversa .
Ciò significa che è necessario "convertire adeguatamente" il puntatore B b
dell'oggetto nel tipo del suo primo membro. Questa conversione non avviene in modo implicito, devi farlo per mezzo di un cast esplicito:
A * a = (A*)&b;
Farlo è ben definito e sicuro, come da parte citata sopra.
Allo stesso modo, al compilatore non è consentito assumere che un puntatore a A
e un puntatore a B
non si alias. La regola del tipo effettivo 6.5.7 ("rigoroso aliasing") fornisce un'eccezione per questo caso:
Un oggetto deve avere il suo valore memorizzato accessibile solo da un'espressione lvalue che ha uno dei seguenti tipi:
...
- un tipo aggregato o unione che include uno dei tipi sopra menzionati tra i suoi membri
Ad esempio, durante l'ottimizzazione un compilatore che chiama la funzione void func (B* b)
non può presumere che una variabile di linage esterna extern A a;
definita in qualche altra unità di traduzione non sia stata modificata dalla funzione.