Warum eine nicht initialisierte globale Variable ein schwaches Symbol ist?

8

Es scheint, dass die nicht initialisierte globale Variable in Gcc als schwaches Symbol behandelt wird. Was ist der Grund dafür?

    
Thomson 11.09.2010, 16:59
quelle

4 Antworten

27

gcc, im C-Modus:

Nicht initialisierte Globals, die nicht als extern deklariert sind, werden als "gewöhnliche" Symbole behandelt, nicht als schwache Symbole.

Gemeinsame Symbole werden zur Verknüpfungszeit zusammengeführt, so dass sie sich alle auf denselben Speicher beziehen; Wenn mehr als ein Objekt versucht, ein solches Symbol zu initialisieren, erhalten Sie einen Link-Zeit-Fehler. (Wenn sie nirgends explizit initialisiert werden, werden sie im BSS platziert, d. H. Mit 0 initialisiert.)

gcc, im C ++ Modus:

Nicht dasselbe - es macht nicht die üblichen Symbole. "Nicht initialisierte" globale Variablen, die nicht als extern deklariert sind, werden implizit mit einem Standardwert initialisiert (0 für einfache Typen oder Standardkonstruktoren).

In beiden Fällen kann ein initialisiertes Symbol durch ein schwaches Symbol durch ein nicht schwach initialisiertes Symbol desselben Namens zur Verknüpfungszeit überschrieben werden.

Um zu veranschaulichen (ich konzentriere mich hier auf den C-Fall), verwende ich 4 Varianten eines Hauptprogramms, die alle gleich sind, mit Ausnahme der Art, wie global deklariert wird:

  1. main_init.c :

    %Vor%
  2. main_uninit.c , wodurch die Initialisierung ausgelassen wird:

    %Vor%
  3. main_uninit_extern.c , wodurch das Schlüsselwort extern hinzugefügt wird:

    %Vor%
  4. main_weak_init.c , wodurch global initialisiert und als schwaches Symbol deklariert wird:

    %Vor%

und another_def.c , die dasselbe global initialisiert:

%Vor%

Die Verwendung von main_uninit.c allein ergibt 0:

%Vor%

Aber wenn another_def.c ebenfalls enthalten ist, wird global explizit initialisiert und wir erhalten das erwartete Ergebnis:

%Vor%

(Beachten Sie, dass dieser Fall fehlschlägt, wenn Sie C ++ verwenden.)

Wenn wir stattdessen mit main_init.c und another.def.c versuchen, haben wir 2 Initialisierungen von global , die nicht funktionieren:

%Vor%

main_uninit_extern.c alleine wird überhaupt nicht funktionieren - das extern Schlüsselwort bewirkt, dass das Symbol eine gewöhnliche externe Referenz und kein gewöhnliches Symbol ist, also beschwert sich der Linker:

%Vor%

Es funktioniert gut, wenn die Initialisierung von another_def.c enthalten ist:

%Vor%

Die Verwendung von main_init_weak.c allein gibt den Wert, mit dem das schwache Symbol initialisiert wurde, an (999) an, da es nichts zu überschreiben gibt:

%Vor%

Aber das Ziehen der anderen Definition von another_def.c funktioniert in diesem Fall, weil die starke Definition dort die schwache Definition in main_init_weak.c überschreibt:

%Vor%     
Matthew Slattery 11.09.2010, 18:13
quelle
9

Die Frage basiert auf einer falschen Prämisse. Nicht initialisierte globale Variablen sind keine schwachen Symbole.

Offenbar bezieht sich die Frage auf die Fähigkeit, dasselbe nicht initialisierte Objekt mit externer Verknüpfung in mehreren Übersetzungseinheiten zu definieren. Formal ist es nicht erlaubt - es ist ein Fehler in C und C ++. Allerdings wird zumindest in C vom C99-Standard als "common extension" der Sprache erkannt, die in vielen realen Compilern implementiert ist

  

J.5 Gemeinsame Erweiterungen

     

J.5.11 Mehrere externe Definitionen

     

1 Es kann mehr als einen externen geben   Definition für die Kennung eines   Objekt, mit oder ohne das Explizite   Verwendung des Keywords extern; wenn die   Definitionen stimmen nicht überein oder mehr als eins   ist initialisiert, das Verhalten ist   undefiniert (6.9.2).

Beachten Sie, dass entgegen der landläufigen Meinung die C-Sprache explizit die Einführung mehrerer Definitionen von Entitäten mit externer Verknüpfung im Programm verbietet, genau wie in C ++.

  

6.9 Externe Definitionen

     

5 Eine externe Definition ist ein   externe Erklärung, die auch a   Definition einer Funktion (außer   eine Inline-Definition) oder ein Objekt. Ob   ein mit external deklarierter Bezeichner   Verknüpfung wird in einem Ausdruck verwendet   (außer als Teil des Operanden von   ein Operator sizeof, dessen Ergebnis ein ist   ganzzahlige Konstante), irgendwo in der   das gesamte Programm soll genau sein   eine externe Definition für die   Kennung; sonst soll es sein    nicht mehr als eins .

Allerdings ist die Erweiterung, die dies erlaubt, bei vielen C-Compilern ziemlich populär, von denen GCC nur eine ist.

    
AnT 11.09.2010 20:11
quelle
3

Hast du das gemeint?

weak.c

%Vor%

strong.c

%Vor%

Beispiellauf

%Vor%

int weak; in weak.c ist eine Deklaration, keine Definition. Oder Sie sagen vielleicht, dass es eine vorläufige Definition ist. Die tatsächliche Definition ist in strong.c , wenn diese Objektdatei im endgültigen Programm oder sonst in weak.c verknüpft ist. Dies ist eine übliche Erweiterung, eine, die gcc verwendet (danke Andrey).

    
pmg 11.09.2010 18:04
quelle
3

Jede Mehrfachdefinition eines globalen Symbols ist ein undefiniertes Verhalten, so dass gcc (oder besser gesagt der GNU Binutils-Linker) frei ist, zu tun, was immer es will. In der Praxis folgt es dem traditionellen Verhalten, um Code zu vermeiden, der auf diesem Verhalten beruht.

    
R.. 11.09.2010 19:21
quelle

Tags und Links