Ich habe mich gefragt, ob ein Extern lokal und eine Registervariable deklariert werden kann. Wenn ja, welche Beschränkungen würden auferlegt?
Können lokale und Registervariablen extern deklariert werden?
Av03
Ciro Santilli OurBigBook.com
Lokale Variablen können in einigen Fällen als extern deklariert werden
Lesen wir die C99 N1256 Standardentwurf.
Der Standard nennt “lokale Variablen” mit “Blockbereich”.
6.7.1/5 “Storage-class specifiers” sagt:
Die Deklaration eines Bezeichners für eine Funktion mit Blockbereich darf außer extern keinen expliziten Speicherklassenbezeichner haben.
Dann für das, was es bedeutet, hinzuzufügen extern
zu einer lokalen Variablen, 6.2.2/4 “Verknüpfungen von Bezeichnern” sagt:
Für einen mit dem Speicherklassenbezeichner extern deklarierten Bezeichner in einem Bereich, in dem eine vorherige Deklaration dieses Bezeichners sichtbar ist, ist die Verknüpfung des Bezeichners bei der späteren Deklaration dieselbe wie die Verknüpfung, wenn die vorherige Deklaration eine interne oder externe Verknüpfung angibt in der vorherigen Erklärung angegeben. Wenn keine vorherige Erklärung sichtbar ist oder wenn die vorherige Erklärung keine Verknüpfung angibt, dann hat der Identifikator eine externe Verknüpfung.
Lassen Sie uns diese Fälle aufschlüsseln.
keine Voranmeldung
void f() {
extern int i;
}
ist das gleiche wie:
extern int i;
void f() {}
außer dass die Deklaration nur innen sichtbar ist f
.
Das ist weil i
hat keine vorherige Erklärung sichtbar. So i
hat eine externe Verknüpfung (die gleiche Verknüpfung wie globale Variablen).
vorherige Erklärung gibt keine Verknüpfung an
int i;
void f() {
extern int i;
}
ist das gleiche wie:
void f() {
extern int i;
}
weil die vorherige Erklärung int i
gibt keine Verknüpfung an, weil Absatz 6 sagt:
Die folgenden Bezeichner haben keine Verknüpfung: ein Bezeichner, der als etwas anderes als ein Objekt oder eine Funktion deklariert ist; ein als Funktionsparameter deklarierter Bezeichner; eine Blockbereichskennung für ein Objekt, das ohne den Speicherklassenbezeichner extern deklariert wurde.
vorherige Erklärung gibt interne oder externe Verknüpfung an
extern int i;
void f() {
extern int i;
}
ist das gleiche wie:
extern int i;
void f() {}
und:
static int i;
void f() {
extern int i;
}
ist das gleiche wie:
static int i;
void f() {}
denn in beiden Fällen haben wir ein vorheriges sichtbares externes und internes (static
) Verknüpfungserklärungen.
Lokale extern initialisieren
Ungültiges C:
void f() {
extern int i = 0;
}
da die Blockbereichsdeklaration eine Initialisierung hat.
Gültige C:
extern int i = 0;
void f() {}
aber wohl schlechter Stil, weil äquivalent zum kürzeren:
int i = 0;
void f() {}
weil 6.7.8 Initialisierung sagt:
Wenn die Deklaration eines Bezeichners einen Blockbereich hat und der Bezeichner eine externe oder interne Verknüpfung hat, darf die Deklaration keinen Initialisierer für den Bezeichner haben.
-
Necroposting, aber – ISO/IEC 9899:1999 6.7.1/p5 spricht nicht von Blockbereichsvariablen, sondern von Blockbereichsfunktionen. Es sagt
void f() { static void g() {} }
ist nur ungültigextern
kann für Funktionsdeklarationen im Blockbereich angegeben werden.– Bleibach
24. März 2018 um 22:06 Uhr
-
@blelbach danke dafür. Gibt es ein analoges Zitat für Variablen oder ist die Antwort falsch? Wenn es ein analoges Zitat für Variablen gibt, können Sie die Antwort damit bearbeiten?
– Ciro Santilli OurBigBook.com
25. März 2018 um 10:22 Uhr
-
Unter „vorherige Erklärung gibt keine Verknüpfung an“ heißt es in dieser Antwort
int i; extern int i;
ist das gleiche wieextern int i;
. Dies ist jedoch nicht der Fall, da das Verhalten undefiniert ist. C 2018 (und 2011 und früher) 6.7 3 gibt die Einschränkung vor, dass, wenn ein Bezeichner keine Verknüpfung hat, es nicht mehr als eine Deklaration davon im selben Geltungsbereich und Namensraum geben darf, mit bestimmten Ausnahmen für Typedef-Namen und -Tags. Seit deri
vonint i;
keine Verknüpfung hat, darf es keine andere Erklärung davon im gleichen Umfang geben. Wenn diese Einschränkung verletzt wird, ist das Verhalten undefiniert.– Eric Postpischil
9. Februar 2021 um 22:09 Uhr
-
C 2018 Abschnitt 6.7 Absatz 3 sagt: „Wenn ein Bezeichner keine Verknüpfung hat, darf es nicht mehr als eine Deklaration des Bezeichners (in einem Deklarator oder Typbezeichner) mit demselben Geltungsbereich und im selben Namensraum geben, außer dass: — a typedef name kann neu definiert werden, um denselben Typ zu bezeichnen wie er es derzeit tut, vorausgesetzt, dass dieser Typ kein variabel modifizierter Typ ist; — Tags können neu deklariert werden, wie in 6.7.2.3 angegeben.“
– Eric Postpischil
10. Februar 2021 um 12:27 Uhr
-
Ja, Umzug
int i
außerhalb der Funktion verschiebt sie in einen neuen Bereich. (Jede zusammengesetzte Anweisung beginnt einen neuen Block [the block for the compound statement that defines a function actually starts at the start of the parameter declarations]ebenso wie Auswahl- und Iterationsanweisungen und ihre Unteranweisungen.) Allerdings whenint i;
außerhalb irgendeiner Funktion liegt, hat es keine Verknüpfung; es hat eine externe Verknüpfung. Für ein Beispiel ohne Verknüpfung, gefolgt von einer externen Verknüpfung, die keine Einschränkungsverletzung darstellt, könnten Sie dies tunvoid f(void) { int i; { extern int i; … } }
.– Eric Postpischil
10. Februar 2021 um 12:33 Uhr
- Können lokale Variablen extern deklariert werden?
Nein. Aber eine globale Variable kann deklariert werden extern
örtlich.
// file1.c
int Count;
// file2.c
void foo(void) {
extern int Count;
Count++;
}
- Können Registervariablen extern deklariert werden?
Nein. Eine Variable darf es nicht sein extern
und register
.
C11 dr 6.7.1 Speicherklassenbezeichner
1 Speicherklassenspezifizierer:
typedef
extern
static
_Thread_local
auto
register
Einschränkungen
2 In den Deklarationsspezifizierern einer Deklaration darf höchstens ein Speicherklassenspezifizierer angegeben werden_Thread_local
kann mit erscheinenstatic
oderextern
)
6.9 Externe Definitionen von C99-Zuständen:
Die Speicherklassenbezeichner auto und register dürfen nicht in den Deklarationsbezeichnern einer externen Deklaration erscheinen.
-
Der Frageabsatz des OP ist nicht sehr klar, aber der Titel fängt die Essenz ein; Ich glaube, das beantwortet nicht, was er/sie gefragt hat.
– Albert Netymk
29. Dezember 2014 um 20:55 Uhr
Sie dürfen nur eine globale Variable als definieren extern
. Dem Compiler (und Linker) mitteilen, dass er woanders definiert ist.
Eine lokale Variable existiert nur im lokalen Gültigkeitsbereich, da sie auf dem Stack oder in einem Register erstellt wird. Wenn die Ausführung nicht (mehr) im Bereich ist, wird der Stack entrollt (damit wieder freier Speicherplatz verfügbar wird) oder das Register wird für andere Dinge verwendet, und die Variable existiert nicht (mehr).
Das Definieren eines lokalen Extern wäre also “seltsam” und unmöglich (aufgrund der Stack-Nutzung).
Albert Netymk
Der Satz register variable
ist mir nicht klar, also würde ich eine kühne Vermutung anstellen, worauf OP wirklich neugierig ist, und die ursprüngliche Frage umformulieren als: Could local variables be declared with extern specifier?
veranschaulicht durch das folgende Snippet:
int main() {
extern int x; // Is this OK?
return 0;
}
Die Antwort ist ja.
Geltungsbereich (Sichtbarkeit) und Speicherung sind zwei unabhängige und miteinander verbundene Konzepte. Hier, x
ist eine lokale Variable (Geltungsbereich) und nur innerhalb dieses Blocks sichtbar. extern
diktiert die Speicherung, was bedeutet, dass dies nur eine Deklaration ist, diese Variable wird woanders definiert. Ich würde den C-Standard als definitive Referenz empfehlen.
Was das weggelassene angeht register
Teil, ich nehme an, OP meinte eine Variable mit register
Speicherklassenspezifizierer, wie register int x
. Dann ist die Angabe illegal register
und extern
zur selben Zeit.
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.
Die symmetrische Frage wäre: ist es gültig zu spezifizieren auto
oder register
mit globalen oder externen Variablen, und genau darum geht es in Alexey Frunzes Antwort.
auto int x; // This is wrong.
int main() {
return 0;
}