Struct-Deklaration
Eine Struktur ist ein Typ, der aus einer Sequenz von Membern besteht, deren Speicherplatz in einer geordneten Sequenz zugewiesen wird (im Gegensatz zu einer Union, die ein Typ ist, der aus einer Sequenz von Membern besteht, deren Speicherplatz sich überlappt).
Der Typ-Spezifizierer für eine Struktur ist identisch mit dem union Typ-Spezifizierer, außer dem verwendeten Schlüsselwort
Inhalt |
[bearbeiten] Syntax
struct attr-spec-seq (optional) name (optional) { struct-declaration-list } |
(1) | ||||||||
struct attr-spec-seq (optional) name |
(2) | ||||||||
struct name ;, *deklariert* sie die Struktur `name`, definiert sie aber nicht (siehe unten Vorwärtsdeklaration). In anderen Kontexten benennt sie die zuvor deklarierte Struktur, und attr-spec-seq ist nicht erlaubt.| name | - | der Name der zu definierenden Struktur |
| struct-declaration-list | - | beliebige Anzahl von Variablendeklarationen, Bitfeld-Deklarationen und static assert-Deklarationen. Member vom unvollständigen Typ und Member vom Funktionstyp sind nicht erlaubt (außer dem flexiblen Array-Member, der unten beschrieben wird) |
| attr-spec-seq | - | (C23)optionale Liste von Attributen, die auf den Strukturtyp angewendet werden |
[bearbeiten] Erklärung
Innerhalb eines Struktur-Objekts nehmen die Adressen seiner Elemente (und die Adressen der Bitfeld-Zuweisungseinheiten) in der Reihenfolge zu, in der die Member definiert wurden. Ein Zeiger auf eine Struktur kann in einen Zeiger auf ihr erstes Element (oder, wenn das Element ein Bitfeld ist, in dessen Zuweisungseinheit) umgewandelt werden. Ebenso kann ein Zeiger auf das erste Element einer Struktur in einen Zeiger auf die umgebende Struktur umgewandelt werden. Es kann unbezeichnete Auffüllung zwischen zwei beliebigen Membern einer Struktur oder nach dem letzten Member geben, aber nicht vor dem ersten Member. Die Größe einer Struktur ist mindestens so groß wie die Summe der Größen ihrer Member.
|
Wenn eine Struktur mindestens einen benannten Member definiert, ist es erlaubt, ihren letzten Member zusätzlich mit einem unvollständigen Array-Typ zu deklarieren. Wenn auf ein Element des flexiblen Array-Members zugegriffen wird (in einem Ausdruck, der den Operator struct s { int n; double d[]; }; // s.d is a flexible array member struct s t1 = { 0 }; // OK, d is as if double d[1], but UB to access struct s t2 = { 1, { 4.2 } }; // error: initialization ignores flexible array // if sizeof (double) == 8 struct s *s1 = malloc(sizeof (struct s) + 64); // as if d was double d[8] struct s *s2 = malloc(sizeof (struct s) + 40); // as if d was double d[5] s1 = malloc(sizeof (struct s) + 10); // now as if d was double d[1]. Two bytes excess. double *dp = &(s1->d[0]); // OK *dp = 42; // OK s1->d[1]++; // Undefined behavior. 2 excess bytes can't be accessed // as double. s2 = malloc(sizeof (struct s) + 6); // same, but UB to access because 2 bytes are // missing to complete 1 double dp = &(s2->d[0]); // OK, can take address just fine *dp = 42; // undefined behavior *s1 = *s2; // only copies s.n, not any element of s.d // except those caught in sizeof (struct s) |
(seit C99) |
|
Ähnlich wie bei Unions wird ein unbenannter Member einer Struktur, dessen Typ eine Struktur ohne name ist, als *anonyme Struktur* bezeichnet. Jeder Member einer anonymen Struktur wird als Member der umschließenden Struktur oder Union betrachtet und behält dessen Speicherlayout. Dies gilt rekursiv, wenn die umschließende Struktur oder Union ebenfalls anonym ist. struct v { union // anonymous union { struct { int i, j; }; // anonymous structure struct { long k, l; } w; }; int m; } v1; v1.i = 2; // valid v1.k = 3; // invalid: inner structure is not anonymous v1.w.k = 5; // valid Ähnlich wie bei Unions ist das Verhalten des Programms undefiniert, wenn eine Struktur ohne benannte Member definiert wird (einschließlich derjenigen, die über anonyme verschachtelte Strukturen oder Unions gewonnen werden). |
(seit C11) |
[bearbeiten] Vorwärtsdeklaration
Eine Deklaration der folgenden Form
struct attr-spec-seq (optional) name ; |
|||||||||
verdeckt jede zuvor deklarierte Bedeutung für den Namen name im Tag-Namensraum und deklariert name als neuen Struktur-Namen im aktuellen Geltungsbereich, der später definiert wird. Bis die Definition erscheint, hat dieser Struktur-Name einen unvollständigen Typ.
Dies ermöglicht es Strukturen, die sich gegenseitig referenzieren
struct y; struct x { struct y *p; /* ... */ }; struct y { struct x *q; /* ... */ };
Beachten Sie, dass ein neuer Struktur-Name auch nur durch die Verwendung eines Struktur-Tags innerhalb einer anderen Deklaration eingeführt werden kann. Wenn jedoch eine zuvor deklarierte Struktur mit demselben Namen im Tag-Namensraum vorhanden ist, bezieht sich das Tag auf diesen Namen.
struct s* p = NULL; // tag naming an unknown struct declares it struct s { int a; }; // definition for the struct pointed to by p void g(void) { struct s; // forward declaration of a new, local struct s // this hides global struct s until the end of this block struct s *p; // pointer to local struct s // without the forward declaration above, // this would point at the file-scope s struct s { char* p; }; // definitions of the local struct s }
[bearbeiten] Schlüsselwörter
[bearbeiten] Hinweise
Siehe struct-Initialisierung für die Regeln bezüglich der Initialisierer für Strukturen.
Da Member vom unvollständigen Typ nicht erlaubt sind und ein Struktur-Typ erst am Ende der Definition als vollständig gilt, kann eine Struktur keinen Member ihres eigenen Typs enthalten. Ein Zeiger auf ihren eigenen Typ ist erlaubt und wird üblicherweise zur Implementierung von Knoten in verknüpften Listen oder Bäumen verwendet.
Da eine Struktur-Deklaration keinen Geltungsbereich festlegt, sind verschachtelte Typen, Aufzählungen und Aufzähler, die durch Deklarationen innerhalb von struct-declaration-list eingeführt werden, im umgebenden Geltungsbereich sichtbar, in dem die Struktur definiert wird.
[bearbeiten] Beispiel
#include <stddef.h> #include <stdio.h> int main(void) { // Declare the struct type. struct car { char* make; int year; }; // Declare and initialize an object of a previously-declared struct type. struct car c = {.year = 1923, .make = "Nash"}; printf("1) Car: %d %s\n", c.year, c.make); // Declare a struct type, an object of that type, and a pointer to it. struct spaceship { char* model; int max_speed; } ship = {"T-65 X-wing starfighter", 1050}, *pship = &ship; printf("2) Spaceship: %s. Max speed: %d km/h\n\n", ship.model, ship.max_speed); // Address increase in order of definition. Padding may be inserted. struct A { char a; double b; char c; }; printf( "3) Offset of char a = %zu\n" "4) Offset of double b = %zu\n" "5) Offset of char c = %zu\n" "6) Size of struct A = %zu\n\n", offsetof(struct A, a), offsetof(struct A, b), offsetof(struct A, c), sizeof(struct A) ); struct B { char a; char b; double c; }; printf( "7) Offset of char a = %zu\n" "8) Offset of char b = %zu\n" "9) Offset of double c = %zu\n" "A) Size of struct B = %zu\n\n", offsetof(struct B, a), offsetof(struct B, b), offsetof(struct B, c), sizeof(struct B) ); // A pointer to a struct can be cast to a pointer // to its first member and vice versa. char** pmodel = (char **)pship; printf("B) %s\n", *pmodel); pship = (struct spaceship *)pmodel; }
Mögliche Ausgabe
1) Car: 1923 Nash 2) Spaceship: T-65 X-wing starfighter. Max speed: 1050 km/h 3) Offset of char a = 0 4) Offset of double b = 8 5) Offset of char c = 16 6) Size of struct A = 24 7) Offset of char a = 0 8) Offset of char b = 1 9) Offset of double c = 8 A) Size of struct B = 16 B) T-65 X-wing starfighter
[bearbeiten] Fehlerberichte
Die folgenden verhaltensändernden Defect Reports wurden rückwirkend auf zuvor veröffentlichte C-Standards angewendet.
| DR | angewendet auf | Verhalten wie veröffentlicht | Korrigiertes Verhalten |
|---|---|---|---|
| DR 499 | C11 | Member von anonymen Strukturen/Unions wurden als Member der umschließenden Struktur/Union betrachtet | sie behalten ihr Speicherlayout |
[bearbeiten] Referenzen
- C23-Standard (ISO/IEC 9899:2024)
- 6.7.2.1 Struktur- und Union-Spezifizierer (S. TBD)
- C17-Standard (ISO/IEC 9899:2018)
- 6.7.2.1 Struktur- und Union-Spezifizierer (S. 81-84)
- C11-Standard (ISO/IEC 9899:2011)
- 6.7.2.1 Struktur- und Union-Spezifizierer (S. 112-117)
- C99-Standard (ISO/IEC 9899:1999)
- 6.7.2.1 Struktur- und Union-Spezifizierer (S. 101-104)
- C89/C90-Standard (ISO/IEC 9899:1990)
- 3.5.2.1 Struktur- und Unionsspezifizierer
[bearbeiten] Siehe auch
| C++ Dokumentation für Klassendeklaration
|