Les variables locales et de registre peuvent-elles être déclarées extern?

Je me demandais si un externe pouvait être déclaré localement et une variable de registre. Si c’était possible, quelles seraient les ressortingctions imposées?

Les variables locales peuvent-elles être déclarées extern?

oui , dans certains cas.

Lisons le projet de norme C99 N1256 .

La norme appelle “variables locales” comme ayant “scope de bloc”.

6.7.1 / 5 Les spécificateurs de classe de stockage indiquent:

La déclaration d’un identifiant pour une fonction ayant une scope de bloc ne doit avoir aucun spécificateur de classe de stockage explicite autre que extern.

Ensuite, pour ce que cela signifie d’append extern à une variable locale, les liens 6.2.2 / 4 d’identificateurs indiquent:

Pour un identifiant déclaré avec le spécificateur de classe de stockage extern dans une étendue dans laquelle une déclaration antérieure de cet identifiant est visible, si la déclaration antérieure spécifie un lien interne ou externe, le lien de l’identifiant dans la déclaration ultérieure est le même que le lien. spécifié lors de la déclaration préalable. Si aucune déclaration préalable n’est visible ou si la déclaration antérieure ne spécifie aucun lien, l’identificateur dispose d’un lien externe.

Permet de décomposer ces cas.

pas de déclaration préalable

 void f() { extern int i; } 

est le même que:

 extern int i; void f() {} 

sauf que la déclaration n’est visible qu’à l’intérieur de f .

C’est parce que i n’ai aucune déclaration préalable visible. i donc un lien externe (le même lien que les variables globales).

déclaration préalable ne spécifie aucun lien

 void f() { int i; extern int i; } 

est le même que:

 void f() { extern int i; } 

parce que la déclaration antérieure int i ne spécifie aucun lien car le paragraphe 6 dit:

Les identificateurs suivants n’ont pas de lien: un identificateur déclaré autre chose qu’un object ou une fonction; un identifiant déclaré comme étant un paramètre de fonction; un identifiant de scope de bloc pour un object déclaré sans le spécificateur de classe de stockage extern.

déclaration préalable spécifie un lien interne ou externe

 extern int i; void f() { extern int i; } 

est le même que:

 extern int i; void f() {} 

et:

 static int i; void f() { extern int i; } 

est le même que:

 static int i; void f() {} 

parce que dans les deux cas, nous avons une précédente déclaration de liaison visible externe et interne ( static ) respectivement.

Initialiser externe externe

C non valide:

 void f() { extern int i = 0; } 

car la déclaration de la scope du bloc a une initialisation.

C valide:

 extern int i = 0; void f() {} 

mais discutablement mauvais style car équivalent au plus court:

 int i = 0; void f() {} 

car 6.7.8 Initialisation dit:

Si la déclaration d’un identifiant a une scope de bloc et que l’identifiant a une liaison externe ou interne, la déclaration ne doit pas avoir d’initialiseur pour l’identifiant.

  1. Les variables locales peuvent-elles être déclarées extern?

Non, mais une variable globale peut être déclarée extern localement.

 // file1.c int Count; // file2.c void foo(void) { extern int Count; Count++; } 
  1. Les variables de registre peuvent-elles être déclarées extern?

Non, une variable ne peut être ni extern ni register .

C11 dr 6.7.1 Spécificateurs de classe de stockage
1 spécificateur de classe de stockage:
typedef
extern
static
_Thread_local
auto
register
Contraintes
2 Au plus, un spécificateur de classe de stockage peut être indiqué dans les spécificateurs de déclaration d’une déclaration, sauf que _Thread_local peut apparaître avec static ou extern )

6.9 Les définitions externes de C99 stipulent:

Les spécificateurs de classe de stockage auto et register ne doivent pas apparaître dans les spécificateurs de déclaration d’une déclaration externe.

Vous êtes uniquement autorisé à définir une variable globale en tant extern . Dire au compilateur (et à l’éditeur de liens) qu’il est défini ailleurs.

Une variable locale n’existe que dans la scope locale, car elle est créée sur la stack ou dans un registre. Lorsque l’exécution n’est pas (plus) dans la scope, la stack est déroulée (de sorte que l’espace libre redevient disponible) ou le registre est utilisé pour autre chose, et la variable n’existe plus (plus).

Donc, définir un externe local serait «étrange» et impossible (en raison de l’utilisation de la stack).

La register variable phrase ne m’est pas claire. Je devrais donc deviner ce qui intéresse vraiment OP et reformuler la question initiale de la manière suivante: Les Could local variables be declared with extern specifier? , illustré par l’extrait suivant:

 int main() { extern int x; // Is this OK? return 0; } 

La réponse est oui.

la scope (visibilité) et le stockage sont deux concepts indépendants et connectés. Ici, x est une variable locale (scope), visible uniquement dans ce bloc. extern dicte le stockage, ce qui signifie qu’il ne s’agit que d’une déclaration, cette variable est définie ailleurs. Je recommanderais le standard C comme référence définitive.

En ce qui concerne la partie register omis, je suppose que OP signifiait une variable avec le register spécificateur de classe de stockage, comme le register int x . Ensuite, il est illégal de spécifier register et extern en même temps.

 int main() { extern auto int x; // This is wrong. return 0; } 

At most, one storage-class specifier may be given in the declaration specifiers in a declaration, except that _Thread_local may appear with static or extern.

La question symésortingque serait: est-il valide de spécifier auto ou register avec des variables globales ou externes, et c’est exactement ce à quoi répond Alexey Frunze.

 auto int x; // This is wrong. int main() { return 0; }