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:
main_init.c :
%Vor%main_uninit.c , wodurch die Initialisierung ausgelassen wird:
%Vor% main_uninit_extern.c , wodurch das Schlüsselwort extern
hinzugefügt wird:
main_weak_init.c , wodurch global
initialisiert und als schwaches Symbol deklariert wird:
und another_def.c , die dasselbe global initialisiert:
%Vor% Die Verwendung von main_uninit.c
allein ergibt 0:
Aber wenn another_def.c
ebenfalls enthalten ist, wird global
explizit initialisiert und wir erhalten das erwartete Ergebnis:
(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:
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:
Es funktioniert gut, wenn die Initialisierung von another_def.c
enthalten ist:
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:
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:
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.
Hast du das gemeint?
weak.c
%Vor%strong.c
%Vor%Beispiellauf
%Vor%
Dies ist eine übliche Erweiterung, eine, die gcc verwendet (danke Andrey). 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.
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.