C sagt, es ist undefiniertes Verhalten.
(C99, 6.9p5) „Wenn ein Identifikator mit externer Bindung erklärt in einem Ausdruck (ausgenommen als Teil des Operanden von einem Operator sizeof Ergebnis dessen ist eine ganzzahlige Konstante) verwendet wird, irgendwo in dem gesamten Programm, es wird genau ein externe Definition für den Identifizierer sein, sonst wird es nicht mehr als ein“
undefiniert Verhalten bedeutet ein Linker den Verknüpfungsvorgang in Anwesenheit von mehreren externen Objektdefinitionen abbrechen kann.
Jetzt Linker sind schön (oder böse, können Sie wählen) und in der Regel Standarderweiterungen müssen mehrere externe Objektdefinitionen handhaben und in einigen Fällen nicht scheitern. Wenn Sie gcc
und ld
von Binutils verwenden, erhalten Sie einen Fehler, wenn Ihre beiden Objekte explizit initialisiert werden. Zum Beispiel haben Sie int x = 0;
in der ersten Übersetzungseinheit und double x = 0.0;
.
Andernfalls, wenn eines der externen Objekte nicht explizit initialisiert wird (die Situation in Ihrem Beispiel) gcc
wird die beiden Objekte in ein Symbol stillschweigend kombinieren. Sie können den Linker dennoch bitten, eine Warnung zu melden, indem Sie ihm die Option --warn-common
übergeben.
Zum Beispiel bei der Verknüpfung der Module:
gcc -Wl,--warn-common module1.o module2.o
den Verknüpfungsvorgang abgebrochen zu erhalten, können Sie den Linker anfordern können alle Warnungen als Fehler mit --fatal-warnings
Option (-Wl,--fatal-warnings,--warn-common
) zu behandeln.
Eine weitere Möglichkeit, den Verknüpfungsprozess abgebrochen zu bekommen, ist die Verwendung der Compileroption -fno-common
, wie in der Antwort von @teppic erläutert. -fno-common
verbietet den externen Objekten, einen gemeinsamen Symboltyp bei der Kompilierung zu erhalten. Wenn Sie dies sowohl für das Modul als auch für den Link tun, erhalten Sie auch den Linkerdefinitionsfehler.
gcc -Wall -fno-common -c module1.c module2.c
gcc module1.o module2.o
Also, in diesem Fall gibt es nur ein "x" in der Symboltabelle? Ich kann einige seltsame Bugs sehen, die daraus resultieren. Thx – amorimluc
@amorimluc in Ihrem Fall Chancen, dass Sie möchten, erhalten einen Fehler von der Linker oder ein einzelnes Objekt in der endgültigen binären und Ihr Programm wird undefiniertes Verhalten aufrufen. – ouah
Ich dachte ich würde, aber es kompiliert und verbindet gut. Und x wird als int gedruckt, aber mit dem Bitmuster des 3.14 float. Dies passiert wahrscheinlich nicht viel im wirklichen Leben, aber es wäre sicher schwer, diesen subtilen Fehler in einem großen Programm zu finden ... – amorimluc