Ich habe Tage in einem seltsamen Problem verbracht und schließlich entdeckt, dass es zwei inline
-Funktion der gleichen Signatur im Projekt gab und sie das Problem verursachten. Um die Situation zu vereinfachen, hier ein Beispiel: zwei cpp-Datei:
a.cpp
%Vor%und b.cpp
%Vor% Bitte beachten Sie, dass inline
functions echo
die gleiche Signatur, aber unterschiedliche Werkzeuge haben. Kompilieren und ausführen
Oder wie das
%Vor% Es druckt 0 0
. (Ich benutzte g ++ 4.6.1 dafür, und ich testete mit clang ++ 2.9, dasselbe Ergebnis)
Das wird nicht passieren, wenn man die Optimierung aktiviert, wie
%Vor% Es ist dieses Mal 0 1
.
Meine Frage ist, egal welches Ergebnis oder wie die Kompilierung funktioniert, es gibt keinen Fehler oder sogar eine Warnung darüber, dass ich inline
Funktionen mehrfach definiert habe. Was in aller Welt passiert mit dem Compiler und Linker in dieser Art von Situation?
BEARBEITEN:
Sehen Sie sich die Symbole in der Objektdatei an
%Vor% Beide Dateien haben den Datensatz echo()
. Also ich denke das Problem passiert zur Zeit der Verbindung. Kann man sagen, dass der Linker zufällig eine Implementierung auswählt und alle anderen verwerfen?
Der Compiler muss diese ODR-Verletzung nicht diagnostizieren, und das ist nicht trivial. Das inline
Schlüsselwort bedeutet, dass verschiedene Übersetzungseinheiten das gleiche Symbol haben können, so dass es vom Compiler als schwach markiert wird. Der grundlegende Anwendungsfall ist eine Funktion, die in einer Kopfzeile inline definiert ist: Alle Übersetzungseinheiten, die die Kopfzeile enthalten, haben die Definition, und das ist völlig in Ordnung. Der Compiler muss nur alle Definitionen bis auf eine löschen und diese Definition überall verwenden.
Es ist ein komplexes Problem festzustellen, ob die verschiedenen Definitionen exakte Übereinstimmungen sind. Der Linker müsste die erzeugte binäre Implementierung analysieren und bestimmen, ob sich die beiden Binärcodes auf denselben Quellcode beziehen oder nicht. Die meisten Compiler haben keine Unterstützung, um dies festzustellen.
Was Ihr spezielles Problem betrifft, kann ich unmöglich die Logik kennen, die dazu führte, dass die beiden Funktionen inline markiert wurden, aber ein häufiger Fehler ist, dass das inline
Schlüsselwort optimieren anstatt klagen Sie nicht über Wiederholungen bei Link-Zeit . Das Schlüsselwort inline
ist in Headern sinnvoll, in cpp-Dateien jedoch nicht so häufig. Wenn Sie in cpp-Dateien einen Teil des Codes in eine Hilfsfunktion einbeziehen möchten, sollte diese Funktion entweder mit static
markiert oder in einem unbenannten -Namespace definiert sein. Wenn die Funktion static
ist, weiß der Compiler, dass alle Verwendungen dieser Funktion in Ihrer Übersetzungseinheit enthalten sind, und er weiß besser, ob er den Funktionsaufruf inline oder nicht ausführen möchte (beachten Sie, dass er auch dann inline sein kann) Sie sagen es nicht, genauso wie es entscheiden kann, nicht zu inline zu gehen, auch wenn Sie es sagen).
Im C ++ - Standard wird angegeben, dass alle Definitionen einer Inline-Funktion identisch sein sollen, aber keine Diagnose erforderlich ist . Das heißt, Ihr Programm ist kein gültiges C ++ - Programm, aber eine Implementierung hat das Recht, diesen Fehler nicht zu erkennen.
Siehe Abschnitt 3.2.5. Es ist zu lang, hier zu posten.
Genau dieser Fall (zwei Inline-Funktionen mit demselben Namen und denselben Signaturen mit unterschiedlichen Implementierungen) führt zu undefiniertem Verhalten . Der Compiler ist nicht erforderlich, um es zu diagnostizieren, obwohl es versuchen könnte.
Tags und Links c++ linker compiler-construction inline redefinition