Können lokale und Registervariablen extern deklariert werden?

Lesezeit: 6 Minuten

Benutzeravatar von Av03
Av03

Ich habe mich gefragt, ob ein Extern lokal und eine Registervariable deklariert werden kann. Wenn ja, welche Beschränkungen würden auferlegt?

Ciro Santilli Benutzeravatar von OurBigBook.com
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ültig extern 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 wie extern 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 der i von int 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 when int 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 tun void f(void) { int i; { extern int i; … } }.

    – Eric Postpischil

    10. Februar 2021 um 12:33 Uhr

  1. 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++;
}
  1. 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 erscheinen static oder extern)

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).

Benutzeravatar von Albert Netymk
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;
}

1432640cookie-checkKönnen lokale und Registervariablen extern deklariert werden?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy