Namespaces
Variants

Declarations

From cppreference.net

Une déclaration est une construction du langage C qui introduit un ou plusieurs identifiants dans le programme et spécifie leur signification et propriétés.

Les déclarations peuvent apparaître dans n'importe quelle portée. Chaque déclaration se termine par un point-virgule (tout comme une instruction ) et consiste en deux (jusqu'à C23) trois (depuis C23) parties distinctes :

specifiers-and-qualifiers declarators-and-initializers  (facultatif) ; (1)
attr-spec-seq specifiers-and-qualifiers declarators-and-initializers ; (2) (depuis C23)
attr-spec-seq ; (3) (depuis C23)

specifiers-and-qualifiers - liste séparée par des espaces, dans n'importe quel ordre,
  • spécificateurs de type :


declarators-and-initializers - liste séparée par des virgules de déclarateurs (chaque déclarateur fournit des informations de type supplémentaires et/ou l'identifiant à déclarer). Les déclarateurs peuvent être accompagnés d' initialiseurs . Les déclarations enum , struct , et union peuvent omettre les déclarateurs , auquel cas elles introduisent uniquement les constantes d'énumération et/ou les étiquettes.
attr-spec-seq - (C23) liste facultative d' attributs , appliquée aux entités déclarées, ou forme une déclaration d'attribut si elle apparaît seule.
1,2) Déclaration simple. Introduit un ou plusieurs identifiants qui désignent des objets, fonctions, étiquettes de struct/union/enum, typedefs ou constantes d'énumération.
3) Déclaration d'attribut. Ne déclare aucun identifiant, et a une signification définie par l'implémentation si la signification n'est pas spécifiée par la norme.

Par exemple,

int a, *b=NULL; // "int" est le spécificateur de type,
                // "a" est un déclarateur
                // "*b" est un déclarateur et NULL est son initialiseur
const int *f(void); // "int" est le spécificateur de type
                    // "const" est le qualificateur de type
                    // "*f(void)" est le déclarateur
enum COLOR {RED, GREEN, BLUE} c; // "enum COLOR {RED, GREEN, BLUE}" est le spécificateur de type
                                 // "c" est le déclarateur

Le type de chaque identifiant introduit dans une déclaration est déterminé par une combinaison du type spécifié par le spécificateur de type et des modifications de type appliquées par son déclarateur . Le type d'une variable peut également être inféré si le spécificateur auto est utilisé. (depuis C23)

Attributs (depuis C23) peuvent apparaître dans specifiers-and-qualifiers , auquel cas ils s'appliquent au type déterminé par les spécificateurs précédents.

Table des matières

Déclarateurs

Chaque déclarateur est l'un des suivants :

identifiant séquence-spécification-attributs  (optionnel) (1)
( déclarateur ) (2)
* séquence-spécification-attributs  (optionnel) qualificateurs  (optionnel) déclarateur (3)
déclarateur-sans-pointeur [ static (optionnel) qualificateurs  (optionnel) expression ]

déclarateur-sans-pointeur [ qualificateurs  (optionnel) * ]

(4)
déclarateur-sans-pointeur ( paramètres-ou-identifiants ) (5)
1) l'identificateur que ce déclarateur introduit.
2) tout déclarateur peut être placé entre parenthèses ; ceci est requis pour introduire des pointeurs vers des tableaux et des pointeurs vers des fonctions.
3) pointeur déclarateur : la déclaration S * cvr D ; déclare D comme un pointeur cvr -qualifié vers le type déterminé par S .
4) déclarateur de tableau : la déclaration S D [ N ] déclare D comme un tableau de N objets du type déterminé par S . noptr-declarator est tout autre déclarateur sauf un déclarateur de pointeur non parenthésé.
5) déclarateur de fonction : la déclaration S D ( params ) déclare D comme une fonction prenant les paramètres params et retournant S . noptr-declarator est tout autre déclarateur sauf un déclarateur de pointeur non parenthésé.

Le raisonnement derrière cette syntaxe est que lorsque l'identifiant déclaré par le déclarateur apparaît dans une expression de la même forme que le déclarateur, il aurait le type spécifié par la séquence de spécificateurs de type.

struct C
{
    int member; // "int" est le spécificateur de type
                // "member" est le déclarateur
} obj, *pObj = &obj;
// "struct C { int member; }" est le spécificateur de type
// le déclarateur "obj" définit un objet de type struct C
// le déclarateur "*pObj" déclare un pointeur vers C,
// l'initialiseur "= &obj" fournit la valeur initiale pour ce pointeur
int a = 1, *p = NULL, f(void), (*pf)(double);
// le spécificateur de type est "int"
// le déclarateur "a" définit un objet de type int
//   l'initialiseur "=1" fournit sa valeur initiale
// le déclarateur "*p" définit un objet de type pointeur vers int
//   l'initialiseur "=NULL" fournit sa valeur initiale
// le déclarateur "f(void)" déclare une fonction prenant void et retournant int
// le déclarateur "(*pf)(double)" définit un objet de type pointeur
//   vers fonction prenant double et retournant int
int (*(*foo)(double))[3] = NULL;
// le spécificateur de type est int
// 1. le déclarateur "(*(*foo)(double))[3]" est un déclarateur de tableau :
//    le type déclaré est "/déclarateur imbriqué/ tableau de 3 int"
// 2. le déclarateur imbriqué est "*(*foo)(double))", qui est un déclarateur de pointeur
//    le type déclaré est "/déclarateur imbriqué/ pointeur vers tableau de 3 int"
// 3. le déclarateur imbriqué est "(*foo)(double)", qui est un déclarateur de fonction
//    le type déclaré est "/déclarateur imbriqué/ fonction prenant double et retournant
//        pointeur vers tableau de 3 int"
// 4. le déclarateur imbriqué est "(*foo)" qui est un déclarateur de pointeur (entre parenthèses, comme requis par
//        la syntaxe du déclarateur de fonction).
//    le type déclaré est "/déclarateur imbriqué/ pointeur vers fonction prenant double
//        et retournant pointeur vers tableau de 3 int"
// 5. le déclarateur imbriqué est "foo", qui est un identifiant.
// La déclaration introduit l'identifiant "foo" pour référencer un objet de type
// "pointeur vers fonction prenant double et retournant pointeur vers tableau de 3 int"
// L'initialiseur "= NULL" fournit la valeur initiale de ce pointeur.
// Si "foo" est utilisé dans une expression de la forme du déclarateur, son type serait
// int.
int x = (*(*foo)(1.2))[0];

La fin de chaque déclarateur qui ne fait pas partie d'un autre déclarateur est un point de séquence .

Dans tous les cas, attr-spec-seq est une séquence facultative d' attributs (depuis C23) . Lorsqu'elle apparaît immédiatement après l'identifiant, elle s'applique à l'objet ou à la fonction en cours de déclaration.

Définitions

Une définition est une déclaration qui fournit toutes les informations sur les identifiants qu'elle déclare.

Chaque déclaration d'un enum ou d'un typedef est une définition.

Pour les fonctions, une déclaration qui inclut le corps de la fonction est une définition de fonction :

int foo(double); // déclaration
int foo(double x) { return x; } // définition

Pour les objets, une déclaration qui alloue du stockage ( automatique ou statique , mais pas extern) est une définition, tandis qu'une déclaration qui n'alloue pas de stockage ( déclaration externe ) n'en est pas une.

extern int n; // déclaration
int n = 10; // définition

Pour les structs et les unions , les déclarations qui spécifient la liste des membres sont des définitions :

struct X; // déclaration
struct X { int n; }; // définition

Redéclaration

Une déclaration ne peut pas introduire un identifiant si une autre déclaration pour le même identifiant dans la même portée apparaît plus tôt, sauf que

  • Les déclarations d'objets avec liaison (externe ou interne) peuvent être répétées :
extern int x;
int x = 10; // OK
extern int x; // OK
static int n;
static int n = 10; // OK
static int n; // OK
  • Non-VLA typedef peut être répété tant qu'il désigne le même type :
typedef int int_t;
typedef int int_t; // OK
struct X;
struct X { int n; };
struct X;

Ces règles simplifient l'utilisation des fichiers d'en-tête.

Notes

En C89, les déclarations dans toute instruction composée (portée de bloc) doivent apparaître au début du bloc, avant toute instruction .

De plus, en C89, les fonctions renvoyant int peuvent être déclarées implicitement par l' opérateur d'appel de fonction et les paramètres de fonction de type int n'ont pas besoin d'être déclarés lors de l'utilisation d'anciennes définitions de fonctions .

(jusqu'à C99)

Les déclarateurs vides sont interdits ; une déclaration simple doit avoir au moins un déclarateur ou déclarer au moins une étiquette de struct/union/enum, ou introduire au moins une constante d'énumération.

Si une partie d'un déclarateur est un tableau à longueur variable (VLA), le type de l'ensemble du déclarateur est appelé "type modifié de manière variable". Les types définis à partir de types modifiés de manière variable sont également modifiés de manière variable (VM).

Les déclarations de tout type modifié de manière variable ne peuvent apparaître qu'au niveau de la portée de bloc ou de la portée de prototype de fonction et ne peuvent pas être membres de structures ou d'unions. Bien qu'un VLA ne puisse avoir qu'une durée de stockage automatique ou allouée, un type VM tel qu'un pointeur vers un VLA peut être statique. Il existe d'autres restrictions sur l'utilisation des types VM, voir goto , switch . longjmp

(depuis C99)

static_asserts sont considérés comme des déclarations du point de vue de la grammaire C (afin qu'ils puissent apparaître partout où une déclaration peut apparaître), mais ils n'introduisent aucun identifiant et ne suivent pas la syntaxe de déclaration.

(depuis C11)

Les déclarations d'attributs sont également considérées comme des déclarations (afin qu'elles puissent apparaître partout où une déclaration peut apparaître), mais elles n'introduisent aucun identifiant. Un simple ; sans attr-spec-seq n'est pas une déclaration d'attribut, mais une instruction.

(depuis C23)

Références

  • Norme C23 (ISO/IEC 9899:2024) :
  • 6.7 Déclarations (p: TBD)
  • Norme C17 (ISO/CEI 9899:2018) :
  • 6.7 Déclarations (p: 78-105)
  • Norme C11 (ISO/CEI 9899:2011) :
  • 6.7 Déclarations (p: 108-145)
  • Norme C99 (ISO/IEC 9899:1999) :
  • 6.7 Déclarations (p: 97-130)
  • Norme C89/C90 (ISO/CEI 9899:1990) :
  • 3.5 Déclarations

Voir aussi

Documentation C++ pour Déclarations