Estensione di Struct in C

Aug 21 2020

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

3 Lundin Aug 21 2020 at 08:19

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 bdell'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 Ae un puntatore a Bnon 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.