Strukturerweiterung in C.

Aug 21 2020

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

3 Lundin Aug 21 2020 at 08:19

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.