Strukturerweiterung in C.
Angenommen, es sind 2 Strukturen wie folgt definiert:
typedef struct {
T x;
T y;
} A;
typedef struct {
A a;
T z;
} B;
Kann ich einen Zeiger auf Struktur B als Zeiger auf Struktur A behandeln?
In der Praxis ist dies zuverlässig / Standard / Portable / Compiler-invariant:
B b = {{1,2},3};
A * a = &b;
print(a->x);
print(a->y);
Antworten
In C17 6.7.2.1 heißt es (Schwerpunkt Mine):
Innerhalb eines Strukturobjekts haben die Nicht-Bitfeldelemente und die Einheiten, in denen sich Bitfelder befinden, Adressen, die in der Reihenfolge zunehmen, in der sie deklariert werden. Ein Zeiger auf ein Strukturobjekt, das entsprechend konvertiert wurde, zeigt auf sein ursprüngliches Element (oder, wenn dieses Element ein Bitfeld ist, auf die Einheit, in der es sich befindet) und umgekehrt .
Dies bedeutet, dass Sie den Zeiger für das B bObjekt "geeignet" in den Typ seines ersten Elements konvertieren müssen . Diese Konvertierung erfolgt nicht implizit. Sie müssen dies mithilfe einer expliziten Besetzung tun:
A * a = (A*)&b;
Dies ist gemäß dem oben genannten Teil genau definiert und sicher.
Ebenso darf der Compiler nicht davon ausgehen, dass ein Zeiger auf Aund ein Zeiger auf Bkeinen Alias. Die Regel des effektiven Typs 6.5.7 ("striktes Aliasing") gibt in diesem Fall eine Ausnahme:
Auf einen gespeicherten Wert eines Objekts darf nur über einen lvalue-Ausdruck zugegriffen werden, der einen der folgenden Typen hat:
...
- ein Aggregat- oder Gewerkschaftstyp, der einen der oben genannten Typen unter seinen Mitgliedern enthält
Beispielsweise void func (B* b)darf ein Compiler, der die Funktion aufruft, während der Optimierung nicht davon ausgehen, dass eine extern A a;in einer anderen Übersetzungseinheit definierte externe Linienvariable von der Funktion nicht geändert wurde.