Struct declaration
Une structure est un type constitué d'une séquence de membres dont le stockage est alloué dans une séquence ordonnée (par opposition à une union, qui est un type constitué d'une séquence de membres dont le stockage se chevauche).
Le
spécificateur de type
pour une structure est identique au
union
spécificateur de type, à l'exception du mot-clé utilisé :
Table des matières |
Syntaxe
struct
attr-spec-seq
(optionnel)
name
(optionnel)
{
struct-declaration-list
}
|
(1) | ||||||||
struct
attr-spec-seq
(optionnel)
name
|
(2) | ||||||||
struct
name
;
,
déclare
mais ne définit pas le struct
name
(voir la déclaration anticipée ci-dessous). Dans d'autres contextes, nomme le struct précédemment déclaré, et
attr-spec-seq
n'est pas autorisé.
| name | - | le nom de la structure en cours de définition |
| struct-declaration-list | - | un nombre quelconque de déclarations de variables, déclarations de champs de bits , et déclarations static_assert . Les membres de type incomplet et les membres de type fonction ne sont pas autorisés (sauf pour le membre de tableau flexible décrit ci-dessous) |
| attr-spec-seq | - | (C23) liste optionnelle d' attributs , appliqués au type de structure |
Explication
Dans un objet struct, les adresses de ses éléments (et les adresses des unités d'allocation des champs de bits) augmentent dans l'ordre dans lequel les membres ont été définis. Un pointeur vers une struct peut être converti en un pointeur vers son premier membre (ou, si le membre est un champ de bits, vers son unité d'allocation). De même, un pointeur vers le premier membre d'une struct peut être converti en un pointeur vers la struct englobante. Il peut y avoir un remplissage sans nom entre deux membres quelconques d'une struct ou après le dernier membre, mais pas avant le premier membre. La taille d'une struct est au moins aussi grande que la somme des tailles de ses membres.
|
Si une structure définit au moins un membre nommé, il est permis de déclarer en plus son dernier membre avec un type de tableau incomplet. Lorsqu'un élément du membre de tableau flexible est accédé (dans une expression utilisant les opérateurs
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) |
(depuis C99) |
|
Similaire à union, un membre sans nom d'une struct dont le type est une struct sans nom est appelé struct anonyme . Chaque membre d'une struct anonyme est considéré comme un membre de la struct ou union englobante, en conservant leur disposition structurelle. Ceci s'applique récursivement si la struct ou union englobante est également anonyme. 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 Similaire à union, le comportement du programme est indéfini si struct est définie sans aucun membre nommé (y compris ceux obtenus via des structs ou unions imbriquées anonymes). |
(depuis C11) |
Déclaration anticipée
Une déclaration de la forme suivante
struct
attr-spec-seq
(optionnel)
name
;
|
|||||||||
masque toute signification précédemment déclarée pour le nom name dans l'espace de noms des balises et déclare name comme un nouveau nom de structure dans la portée actuelle, qui sera défini ultérieurement. Jusqu'à ce que la définition apparaisse, ce nom de structure a un type incomplet .
Cela permet aux structures de se référer mutuellement :
struct y; struct x { struct y *p; /* ... */ }; struct y { struct x *q; /* ... */ };
` n'a pas été traduit conformément aux instructions, car il s'agit de code source qui doit rester inchangé. La structure HTML et les attributs ont également été préservés.
Notez qu'un nouveau nom de struct peut également être introduit simplement en utilisant une étiquette de struct dans une autre déclaration, mais si une struct précédemment déclarée avec le même nom existe dans l'espace de noms name space des étiquettes, l'étiquette se référerait à ce nom
struct s* p = NULL; // l'étiquette nommant une structure inconnue la déclare struct s { int a; }; // définition de la structure pointée par p void g(void) { struct s; // déclaration anticipée d'une nouvelle structure s locale // cela masque la structure s globale jusqu'à la fin de ce bloc struct s *p; // pointeur vers la structure s locale // sans la déclaration anticipée ci-dessus, // cela pointerait vers la structure s de portée fichier struct s { char* p; }; // définition de la structure s locale }
Mots-clés
Notes
Voir l'initialisation de struct pour les règles concernant les initialiseurs des structs.
Parce que les membres de type incomplet ne sont pas autorisés, et qu'un type struct n'est pas complet avant la fin de la définition, une struct ne peut pas avoir un membre de son propre type. Un pointeur vers son propre type est autorisé, et est couramment utilisé pour implémenter des nœuds dans des listes chaînées ou des arbres.
Parce qu'une déclaration de struct n'établit pas scope , les types imbriqués, les énumérations et les énumérateurs introduits par les déclarations dans struct-declaration-list sont visibles dans la portée environnante où la struct est définie.
Exemple
#include <stddef.h> #include <stdio.h> int main(void) { // Déclarer le type struct. struct car { char* make; int year; }; // Déclarer et initialiser un objet d'un type struct précédemment déclaré. struct car c = {.year = 1923, .make = "Nash"}; printf("1) Car: %d %s\n", c.year, c.make); // Déclarer un type struct, un objet de ce type et un pointeur vers celui-ci. 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); // L'adresse augmente dans l'ordre de définition. Du remplissage peut être inséré. 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) ); // Un pointeur vers une struct peut être converti en pointeur // vers son premier membre et vice versa. char** pmodel = (char **)pship; printf("B) %s\n", *pmodel); pship = (struct spaceship *)pmodel; }
Sortie possible :
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
Rapports de défauts
Les rapports de défauts modifiant le comportement suivants ont été appliqués rétroactivement aux normes C publiées antérieurement.
| DR | Applicable à | Comportement publié | Comportement corrigé |
|---|---|---|---|
| DR 499 | C11 | les membres des structures/unions anonymes étaient considérés comme membres de la structure/union englobante | ils conservent leur disposition en mémoire |
Références
- Norme C23 (ISO/IEC 9899:2024) :
-
- 6.7.2.1 Spécificateurs de structure et d'union (p: TBD)
- Norme C17 (ISO/CEI 9899:2018) :
-
- 6.7.2.1 Spécificateurs de structure et d'union (p: 81-84)
- Norme C11 (ISO/IEC 9899:2011):
-
- 6.7.2.1 Spécificateurs de structure et d'union (p: 112-117)
- Norme C99 (ISO/CEI 9899:1999) :
-
- 6.7.2.1 Spécificateurs de structure et d'union (p: 101-104)
- Norme C89/C90 (ISO/CEI 9899:1990) :
-
- 3.5.2.1 Spécificateurs de structure et d'union
Voir aussi
|
Documentation C++
pour
Déclaration de classe
|