Externe, interne und keine Verlinkung oder warum geht das nicht?

Lesezeit: 5 Minuten

Benutzer-Avatar
Benutzer6898756

Nach C-Norm:

In dem Satz von Übersetzungseinheiten und Bibliotheken, die ein ganzes Programm bilden, trägt jede Deklaration eine bestimmte Kennung mit
externe Verknüpfung
bezeichnet dasselbe Objekt oder dieselbe Funktion. Innerhalb einer Übersetzungseinheit ist jede Deklaration eines Bezeichners mit
interne Verknüpfung
bezeichnet dasselbe Objekt oder dieselbe Funktion. Jede Deklaration eines Bezeichners mit
keine Verknüpfung
bezeichnet eine einzigartige Entität.

In meinem Beispiel haben wir drei separate Deklarationen, wobei jeder Bezeichner eine andere Verknüpfung hat. Warum funktioniert das nicht?

static int a; //a_Internal

int main(void) {
    int a; //a_Local
    {
        extern int a; //a_External
    }
    return 0;
}

Fehler:

In Funktion ‘main’: Zeile 9: Fehler: Variable, die zuvor als ‘statisch’ deklariert wurde, wurde als ‘extern’ neu deklariert

Warum besteht der Compiler darauf, dass ich neu deklariere, anstatt zu versuchen, auf ein externes Objekt in einer anderen Datei zuzugreifen?

Gültiges C++-Beispiel als Referenz:

static void f();
static int i = 0;               // #1
void g() {
  extern void f();              // internal linkage
  int i;                        // #2 i has no linkage
  {
    extern void f();            // internal linkage
    extern int i;               // #3 external linkage
  }
}

Sowohl Clang als auch VC scheinen mit meinem C-Beispiel in Ordnung zu sein; nur einige Versionen von GCC (nicht alle) erzeugen den oben genannten Fehler.

  • Also, Sie haben Absatz 2 gelesen, gut, versuchen Sie jetzt, Absatz 6 zu lesen, dann Absatz 4, auch danach, wenn Sie Fragen haben, kommen Sie bitte zurück. 🙂

    – Sourav Ghosh

    29. September 2016 um 10:12 Uhr


  • Mit gcc bekommt man diesen Fehler, aber nicht mit clang.

    – Jabberwocky

    29. September 2016 um 10:14 Uhr

  • (Fun Fact: In C++ wird dieser Code (als gültig!) im Beispiel in erwähnt [basic.link]/6.)

    – Kerrek SB

    29. September 2016 um 10:15 Uhr


  • Ich habe alle Absätze gelesen und kein einziges Mal. a_Local hat keine Verknüpfung, richtig.

    – Benutzer6898756

    29. September 2016 um 10:19 Uhr

  • @KerrekSB Könntest du deinen Link reparieren? Denn jetzt frage ich mich, warum sich C++ anders verhält.

    – Benutzer6898756

    29. September 2016 um 10:48 Uhr

Benutzer-Avatar
PP

§6.2.2, 7 sagt:

Wenn innerhalb einer Übersetzungseinheit derselbe Bezeichner sowohl bei interner als auch bei externer Verknüpfung erscheint, ist das Verhalten undefiniert.

Also, Ihr Programm hat undefiniertes Verhalten.

§6.2.2, 4 sagt das

extern int a; //a_External

hat eine externe Verknüpfung, da die vorherige Erklärung im Geltungsbereich sichtbar ist int a; //a_Local hat keine Verknüpfung. Aber

static int a; //a_Internal

erklärt a mit interner Verlinkung. Daher ist es nicht definiert gemäß §6.2.2, 7.

  • An diese Ausnahme habe ich anscheinend nicht gedacht. Irgendeine Begründung für diese Aussage?

    – Benutzer6898756

    29. September 2016 um 10:31 Uhr

  • @ user6898756 Begründung: Verbot unverständlicher Ergebnisse bizarrer und esoterischer Regeln ohne erkennbaren Nutzen? Nur vielleicht? Plus vielleicht eine bessere Chance, einen korrekten Compiler und Linker zu bauen.

    – Peter – Setzen Sie Monica wieder ein

    29. September 2016 um 17:31 Uhr


Benutzer-Avatar
tversteeg

Der Compiler gibt diesen Fehler aus, weil innerhalb der a_External Umfang, a_Internal ist immer noch zugänglich, also redeklarieren Sie a_Internal aus static zu extern in a_External wegen der Namenskollision von a. Dieses Problem kann durch die Verwendung unterschiedlicher Variablennamen gelöst werden, zum Beispiel:

static int a1; //a_Internal

int main(void) {
    int a2; //a_Local
    {
        extern int a3; //a_External
    }
    return 0;
}

  • Mit Ihrer Erklärung sollte a_Local auch nicht funktionieren.

    – Benutzer6898756

    29. September 2016 um 10:23 Uhr

  • FYI: Wenn ein Bezeichner zwei verschiedene Entitäten im selben Namensraum bezeichnet, können sich die Geltungsbereiche überschneiden. Wenn dies der Fall ist, endet der Geltungsbereich einer Entität (der innere Geltungsbereich ) direkt vor dem Geltungsbereich der anderen Entität (der äußere Geltungsbereich ). Innerhalb des inneren Geltungsbereichs bezeichnet der Bezeichner die im inneren Geltungsbereich deklarierte Entität; Die im äußeren Geltungsbereich deklarierte Entität ist im inneren Geltungsbereich verborgen (und nicht sichtbar)..

    – Benutzer6898756

    29. September 2016 um 10:26 Uhr


  • @ user6898756 so funktioniert es nicht, siehe Zitat in der Frage: Alle Deklarationen von Bezeichnern mit Verknüpfung bezeichnen dieselbe Entität (sie verbergen keine andere Deklaration mit Verknüpfung)

    – MM

    29. September 2016 um 11:28 Uhr

  • @MM, auf das ich mich bezog innerhalb des Bereichs a_External ist a_Internal weiterhin zugänglich. Nein, ist es nicht. Es wird durch eine a_External-Deklaration versteckt. Die einzige Möglichkeit, auf a_Internal zuzugreifen, ist dieselbe Verknüpfungsregel, die ich zitiert habe.

    – Benutzer6898756

    29. September 2016 um 11:46 Uhr

  • @MM Der zitierte Text bestimmt, dass „jede Deklaration eines bestimmten Bezeichners mit extern Verknüpfung bezeichnet das gleiche Objekt“, und es verfügt auch, dass „jede Deklaration eines Bezeichners mit intern Verknüpfung bezeichnet das gleiche Objekt“. Wie bei jeder natürlichen Sprache steht die Semantik auf dem Spiel, aber eine mögliche Interpretation ist, dass wir zwei unterschiedliche und nicht verwandte Sätze “gleicher” Objekte haben, solche mit interner Verknüpfung und solche mit externer Verknüpfung. …

    – Peter – Setzen Sie Monica wieder ein

    29. September 2016 um 17:39 Uhr


Benutzer-Avatar
msc

C-Standard sagt:

In der Menge der Übersetzungseinheiten bezeichnet jede Deklaration eines bestimmten Bezeichners mit externer Verknüpfung dieselbe Entität (Objekt oder Funktion). Innerhalb einer Übersetzungseinheit bezeichnet jede Deklaration eines Bezeichners mit interner Verknüpfung dieselbe Entität.

In der Gruppe von Übersetzungseinheiten können wir nicht mehrere unterschiedliche externe Entitäten mit demselben Namen haben, daher sollten die Typen jeder Deklaration, die diese einzelne externe Entität bezeichnet, übereinstimmen. Wir können prüfen, ob die Typen innerhalb einer Übersetzungseinheit übereinstimmen, dies geschieht zur Kompilierzeit. Wir können weder zur Kompilierzeit noch zur Linkzeit prüfen, ob die Typen zwischen verschiedenen Übersetzungseinheiten übereinstimmen.

Für einen mit dem Speicherklassen-Spezifizierer extern deklarierten Bezeichner in einem Bereich, in dem eine vorherige Deklaration dieses Bezeichners sichtbar ist,31) wenn die vorherige Deklaration eine interne oder externe Verknüpfung angibt, ist die Verknüpfung des Bezeichners bei der späteren Deklaration dieselbe wie die bei der vorherigen Erklärung angegebene Verknüpfung. 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.

static int a; //a_Internal

int main(void) {
    int a; //No linkage
    {
        extern int a; //a_External
    }
    return 0;
}

Hier hat die vorherige Deklaration des Bezeichners a keine Verknüpfung, also extern int a hat eine externe Verlinkung. Das bedeutet, dass wir int a in einer anderen Übersetzungseinheit definieren müssen. Jedoch GCC beschlossen, diesen Code mit zuvor deklarierter Variable abzulehnen static neu deklarierter ‘extern’-Fehler, wahrscheinlich weil wir undefiniertes Verhalten gemäß haben C Standard.

1158200cookie-checkExterne, interne und keine Verlinkung oder warum geht das nicht?

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

Privacy policy