GOOGLE ADS

Mittwoch, 13. April 2022

Was ist ein undefinierter Verweis/ungelöster externer Symbolfehler und wie behebe ich ihn?

Was sind undefinierte Referenz-/ungelöste externe Symbolfehler? Was sind häufige Ursachen und wie können sie behoben/verhindert werden?


Lösung des Problems

Das Kompilieren eines C++-Programms erfolgt in mehreren Schritten, wie in 2.2 angegeben (Dank an Keith Thompson für die Referenz):

Der Vorrang unter den Syntaxregeln der Übersetzung wird durch die folgenden Phasen festgelegt [siehe Fußnote].

  • Physische Quelldateizeichen werden auf eine durch die Implementierung definierte Weise auf den grundlegenden Quellzeichensatz abgebildet (Einführung von Zeilenumbruchzeichen für Zeilenendeindikatoren), falls erforderlich. [SNIP]

  • Jedes Vorkommen eines Backslash-Zeichens (\), unmittelbar gefolgt von einem Zeilenumbruchzeichen, wird gelöscht, wodurch physische Quellzeilen gespleißt werden, um logische Quellzeilen zu bilden. [SNIP]

  • Die Quelldatei wird in Vorverarbeitungstoken (2.5) und Folgen von Leerzeichen (einschließlich Kommentaren) zerlegt. [SNIP]

  • Vorverarbeitungsanweisungen werden ausgeführt, Makroaufrufe werden erweitert und unäre _Pragma-Operatorausdrücke werden ausgeführt. [SNIP]

  • Jedes Element des Quellzeichensatzes in einem Zeichenliteral oder einem Zeichenfolgenliteral sowie jede Escape-Sequenz und jeder universelle Zeichenname in einem Zeichenliteral oder einem nicht unformatierten Zeichenfolgenliteral wird in das entsprechende Element des Ausführungszeichensatzes konvertiert. [SNIP]

  • Benachbarte String-Literal-Tokens werden verkettet.

  • Leerzeichen, die Token trennen, spielen keine Rolle mehr. Jedes Vorverarbeitungstoken wird in ein Token umgewandelt. (2.7). Die resultierenden Token werden syntaktisch und semantisch analysiert und als Übersetzungseinheit übersetzt. [SNIP]

  • Übersetzte Übersetzungseinheiten und Instantiierungseinheiten werden wie folgt kombiniert: [SNIP]

  • Alle Verweise auf externe Entitäten werden aufgelöst. Bibliothekskomponenten werden verknüpft, um externe Verweise auf Entitäten zu erfüllen, die in der aktuellen Übersetzung nicht definiert sind. Alle diese Übersetzungsausgaben werden in einem Programmbild gesammelt, das Informationen enthält, die für die Ausführung in seiner Ausführungsumgebung benötigt werden. (Hervorhebung von mir)

  • [Fußnote] Implementierungen müssen sich so verhalten, als ob diese getrennten Phasen auftreten, obwohl in der Praxis verschiedene Phasen zusammengefaltet werden können.

    Die angegebenen Fehler treten während dieser letzten Phase der Kompilierung auf, die am häufigsten als Verknüpfung bezeichnet wird. Es bedeutet im Grunde, dass Sie eine Reihe von Implementierungsdateien in Objektdateien oder Bibliotheken kompiliert haben und diese nun zusammenarbeiten lassen möchten.

    Angenommen, Sie haben das Symbol ain definiert a.cpp. Nun, b.cpp deklarierte dieses Symbol und benutzte es. Vor dem Verknüpfen geht es einfach davon aus, dass dieses Symbol irgendwo definiert wurde, aber es ist noch egal, wo. Die Verknüpfungsphase ist dafür verantwortlich, das Symbol zu finden und es korrekt mit b.cpp(nun, eigentlich mit dem Objekt oder der Bibliothek, die es verwendet) zu verknüpfen.

    Wenn Sie Microsoft Visual Studio verwenden, sehen Sie, dass Projekte .libDateien generieren. Diese enthalten eine Tabelle mit exportierten Symbolen und eine Tabelle mit importierten Symbolen. Die importierten Symbole werden anhand der Bibliotheken aufgelöst, mit denen Sie verknüpfen, und die exportierten Symbole werden für die Bibliotheken bereitgestellt, die diese verwenden .lib(falls vorhanden).

    Ähnliche Mechanismen existieren für andere Compiler/Plattformen.

    Häufige Fehlermeldungen sind error LNK2001, error LNK1120, error LNK2019für Microsoft Visual Studio und undefined reference to symbolName für GCC.

    The code:

    struct X
    {
    virtual void foo();
    };
    struct Y: X
    {
    void foo() {}
    };
    struct A
    {
    virtual ~A() = 0;
    };
    struct B: A
    {
    virtual ~B(){}
    };
    extern int x;
    void foo();
    int main()
    {
    x = 0;
    foo();
    Y y;
    B b;
    }

    generiert die folgenden Fehler mit GCC:

    /home/AbiSfw/ccvvuHoX.o: In function `main':
    prog.cpp:(.text+0x10): undefined reference to `x'
    prog.cpp:(.text+0x19): undefined reference to `foo()'
    prog.cpp:(.text+0x2d): undefined reference to `A::~A()'
    /home/AbiSfw/ccvvuHoX.o: In function `B::~B()':
    prog.cpp:(.text._ZN1BD1Ev[B::~B()]+0xb): undefined reference to `A::~A()'
    /home/AbiSfw/ccvvuHoX.o: In function `B::~B()':
    prog.cpp:(.text._ZN1BD0Ev[B::~B()]+0x12): undefined reference to `A::~A()'
    /home/AbiSfw/ccvvuHoX.o:(.rodata._ZTI1Y[typeinfo for Y]+0x8): undefined reference to `typeinfo for X'
    /home/AbiSfw/ccvvuHoX.o:(.rodata._ZTI1B[typeinfo for B]+0x8): undefined reference to `typeinfo for A'
    collect2: ld returned 1 exit status

    und ähnliche Fehler mit Microsoft Visual Studio:

    1>test2.obj: error LNK2001: unresolved external symbol "void __cdecl foo(void)" (?foo@@YAXXZ)
    1>test2.obj: error LNK2001: unresolved external symbol "int x" (?x@@3HA)
    1>test2.obj: error LNK2001: unresolved external symbol "public: virtual __thiscall A::~A(void)" (??1A@@UAE@XZ)
    1>test2.obj: error LNK2001: unresolved external symbol "public: virtual void __thiscall X::foo(void)" (?foo@X@@UAEXXZ)
    1>...\test2.exe: fatal error LNK1120: 4 unresolved externals

    Häufige Ursachen sind:


    • Versäumnis, mit geeigneten Bibliotheken/Objektdateien zu verknüpfen oder Implementierungsdateien zu kompilieren

    • Deklarierte und undefinierte Variable oder Funktion.

    • Häufige Probleme mit Klassentypmitgliedern

    • Vorlagenimplementierungen nicht sichtbar.

    • Symbole wurden in einem C-Programm definiert und in C++-Code verwendet.

    • Falsches Importieren/Exportieren von Methoden/Klassen über Module/DLLs hinweg. (MSVS-spezifisch)

    • Zirkuläre Bibliotheksabhängigkeit

    • undefinierter Verweis auf `WinMain@16'

    • Interdependente Bibliotheksordnung

    • Mehrere Quelldateien mit demselben Namen

    • Tippfehler oder Nichteinschließen der.lib-Erweiterung bei Verwendung von #pragma(Microsoft Visual Studio)

    • Probleme mit Vorlagenfreunden

    • Widersprüchliche UNICODEDefinitionen

    • Fehlendes „extern" in konstanten Variablendeklarationen/-definitionen (nur C++)

    Keine Kommentare:

    Kommentar veröffentlichen

    Warum werden SCHED_FIFO-Threads derselben physischen CPU zugewiesen, obwohl CPUs im Leerlauf verfügbar sind?

    Lösung des Problems Wenn ich das richtig verstehe, versuchen Sie, SCHED_FIFO mit aktiviertem Hyperthreading ("HT") zu verwenden, ...