Namespaces
Variants

External and tentative definitions

From cppreference.net

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 inline pour les détails sur les définitions de fonctions inline.

(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