External and tentative definitions
Au niveau supérieur d'une unité de traduction (c'est-à-dire un fichier source avec tous les #includes après le préprocesseur), chaque programme C est une séquence de déclarations , qui déclarent des fonctions et des objets avec liaison externe ou interne . Ces déclarations sont appelées déclarations externes car elles apparaissent en dehors de toute fonction.
extern int n; // déclaration externe avec liaison externe int b = 1; // définition externe avec liaison externe static const char *c = "abc"; // définition externe avec liaison interne int f(void) // définition externe avec liaison externe { int a = 1; // non-externe return b; } static void x(void) // définition externe avec liaison interne { }
Les objets déclarés avec une déclaration externe ont une durée de stockage statique, et en tant que tels ne peuvent pas utiliser les spécificateurs auto ou register sauf que auto peut être utilisé pour l'inférence de type (depuis C23) . Les identifiants introduits par les déclarations externes ont une portée de fichier .
Table des matières |
Définitions provisoires
Une définition provisoire est une déclaration externe sans initialiseur, et soit sans spécificateur de classe de stockage soit avec le spécificateur static .
Une définition provisoire est une déclaration qui peut ou non agir comme une définition. Si une définition externe réelle est trouvée plus tôt ou plus tard dans la même unité de traduction, alors la définition provisoire agit simplement comme une déclaration.
int i1 = 1; // définition, liaison externe int i1; // définition provisoire, agit comme déclaration car i1 est défini extern int i1; // déclaration, fait référence à la définition précédente extern int i2 = 3; // définition, liaison externe int i2; // définition provisoire, agit comme déclaration car i2 est défini extern int i2; // déclaration, fait référence à la définition à liaison externe
S'il n'y a pas de définitions dans la même unité de traduction, alors la définition provisoire agit comme une définition réelle qui initialise à vide l'objet.
int i3; // définition provisoire, liaison externe int i3; // définition provisoire, liaison externe extern int i3; // déclaration, liaison externe // dans cette unité de traduction, i3 est défini comme par "int i3 = 0;"
Contrairement aux déclarations extern , qui ne modifient pas la liaison d'un identifiant si une déclaration antérieure l'a établie, les définitions provisoires peuvent être en désaccord quant à la liaison avec une autre déclaration du même identifiant. Si deux déclarations pour le même identifiant sont dans la portée et ont des liaisons différentes, le comportement est indéfini :
static int i4 = 2; // définition, liaison interne int i4; // Comportement indéfini : désaccord de liaison avec la ligne précédente extern int i4; // déclaration, fait référence à la définition à liaison interne static int i5; // définition provisoire, liaison interne int i5; // Comportement indéfini : désaccord de liaison avec la ligne précédente extern int i5; // fait référence à la précédente, dont la liaison est interne
Une définition provisoire avec liaison interne doit avoir un type complet.
static int i[]; // Erreur, type incomplet dans une définition tentatative statique int i[]; // OK, équivalent à int i[1] = {0}; sauf si redéclaré ultérieurement dans ce fichier
Règle de définition unique
Chaque unité de traduction peut avoir zéro ou une définition externe de chaque identifiant avec liaison interne (une variable globale static ).
Si un identifiant avec une liaison interne est utilisé dans une expression autre qu'une
non-VLA,
(depuis C99)
sizeof
,
_Alignof
(depuis C11)
(jusqu'à C23)
,
alignof
(depuis C23)
, ou
typeof
(depuis C23)
, il doit y avoir une et une seule définition externe pour cet identifiant dans l'unité de traduction.
Le programme entier peut avoir zéro ou une définition externe pour chaque identifiant avec liaison externe .
Si un identifiant avec liaison externe est utilisé dans toute expression autre qu'une
non-VLA,
(depuis C99)
sizeof
,
_Alignof
(depuis C11)
(jusqu'à C23)
,
alignof
(depuis C23)
, ou
typeof
(depuis C23)
, il doit y avoir une et une seule définition externe pour cet identifiant quelque part dans le programme entier.
Notes
|
Les définitions inline dans différentes unités de traduction ne sont pas contraintes par la règle de définition unique. Voir
|
(depuis C99) |
Voir durée de stockage et liaison pour la signification du mot-clé extern avec les déclarations au niveau de la portée du fichier
Voir definitions pour la distinction entre déclarations et définitions.
Les définitions tentatives ont été inventées pour normaliser diverses approches pré-C89 visant à déclarer en avant des identificateurs avec liaison interne.
Références
- Norme C23 (ISO/CEI 9899:2024) :
-
- 6.9 Définitions externes (p: TBD)
- Norme C17 (ISO/CEI 9899:2018) :
-
- 6.9 Définitions externes (p: 113-116)
- Norme C11 (ISO/IEC 9899:2011) :
-
- 6.9 Définitions externes (p: 155-159)
- Norme C99 (ISO/CEI 9899:1999) :
-
- 6.9 Définitions externes (p: 140-144)
- Norme C89/C90 (ISO/IEC 9899:1990) :
-
- 3.7 DÉFINITIONS EXTERNES