1445 votes

Ce qui est une référence non définie/externe non résolu symbole d'erreur et comment la corriger?

Quelles sont undefined reference/externe non résolu les erreurs de symboles? Quelles sont les causes les plus courantes et comment les corriger ou prévenir?

N'hésitez pas à modifier/ajouter votre propre.

818voto

Luchian Grigore Points 136646

La compilation d'un programme C++ se déroule en plusieurs étapes, comme spécifié par 2.2 (crédits de Keith Thompson pour la référence):

La préséance entre les règles de syntaxe de la traduction est fixée par les phases suivantes [voir note de bas de page].

  1. Source physique de fichier caractères sont mis en correspondance, la mise en œuvre définies de manière à la source de base de jeu de caractères (introduction de la nouvelle ligne de caractères de fin de ligne des indicateurs) si nécessaire. [SNIP]
  2. Chaque instance d'un caractère barre oblique inverse (\) immédiatement suivie d'une nouvelle ligne de caractère est supprimé, l'épissage source physique des lignes de la forme logique de la source de lignes. [SNIP]
  3. Le fichier source est décomposé en un prétraitement des jetons (2.5) et des séquences de caractères d'espacement (y compris les commentaires). [SNIP]
  4. Prétraitement des directives sont exécutées, macro invocations sont élargies, et _Pragma opérateur unaire expressions sont exécutées. [SNIP]
  5. Chaque source de jeu de caractères membre dans un littéral de caractère ou une chaîne de caractères littérale, ainsi que chaque séquence d'échappement et universelle-personnage-nom un caractère littéral ou non raw littéral de chaîne est convertie le membre correspondant de l'exécution du jeu de caractères; [SNIP]
  6. Adjacent littéral de chaîne de tokens sont concaténées.
  7. Des espaces blancs séparant les jetons sont pas plus importante. Chaque prétraitement jeton est converti en un jeton. (2.7). L' résultant des jetons sont syntaxiquement et sémantiquement analysé et traduit comme une unité de traduction. [SNIP]
  8. Traduit unités de traduction et d'instanciation unités sont combinées comme suit: [SNIP]
  9. Toutes les références d'entité sont résolus. Bibliothèque de composants sont liés à satisfaire les exigences des références à des entités qui ne sont pas définis dans le traduction en cours. Tous ces traducteur de sortie est prélevé dans un programme image qui contient les informations nécessaires pour l'exécution de ses environnement d'exécution. (l'emphase est mienne)

[note de bas de page] Implémentations doivent se comporter comme si ces phases distinctes se produire, même si dans la pratique les différentes phases peuvent être pliés.

Les spécifiés des erreurs se produisent au cours de cette dernière étape de la compilation, plus communément appelée la liaison. Cela signifie essentiellement que vous avez compilé un groupe de fichiers de mise en œuvre dans les fichiers objets ou des bibliothèques et maintenant vous voulez les faire travailler ensemble.

Dire vous avez défini le symbole a en a.cpp. Maintenant, b.cpp a déclaré que le symbole et l'a utilisé. Avant la liaison, il suppose simplement que ce symbole a été défini quelque part, mais il n'a pas encore de soins où. Le lien entre la phase est responsable de trouver le symbole et correctement reliant b.cpp (eh bien, en fait, à l'objet ou à la bibliothèque qui l'utilise).

Si vous utilisez MSVS, vous verrez que les projets génèrent .lib fichiers. Ceux-ci contiennent une table de symboles exportés, et une table de symboles importés. Les symboles importés sont résolues contre les bibliothèques de lien en face de vous, et les symboles exportés sont fournis pour les bibliothèques qui utilisent cette .lib (le cas échéant).

Mécanisme similaire existe pour d'autres compilateurs/plates-formes.

Messages d'erreur courants error LNK2001, error LNK1120 pour MSVS et undefined reference to symbolName pour la gcc.

Le 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;
}

permettraient de générer les erreurs suivantes avec 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

et des erreurs similaires avec MSVS:

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

Les causes courantes comprennent:

172voto

Luchian Grigore Points 136646

Les membres de la classe:

Un pur virtual destructeur besoins de mise en œuvre.

Déclarer un destructeur pur nécessite encore à vous de le définir (à la différence d'une fonction régulière):

struct X
{
    virtual ~X() = 0;
};
struct Y : X
{
    ~Y() {}
};
int main()
{
    Y y;
}
//X::~X(){} //uncomment this line for successful definition

Cela se produit parce que classe de base les destructeurs sont appelés lorsque l'objet est détruit implicitement, si une définition est nécessaire.

virtual méthodes doivent être mises en œuvre ou définis comme pure.

Ceci est similaire à la non-virtual méthodes avec pas de définition, avec l'ajout de raisonnement que la pure déclaration génère un mannequin vtable et vous risquez d'obtenir l'erreur liens sans l'aide de la fonction:

struct X
{
    virtual void foo();
};
struct Y : X
{
   void foo() {}
};
int main()
{
   Y y; //linker error although there was no call to X::foo
}

Pour que cela fonctionne, déclarer X::foo() pure:

struct X
{
    virtual void foo() = 0;
};

Non-virtual des membres de la classe

Certains membres ont besoin d'être définies, même si pas utilisé explicitement:

struct A
{ 
    ~A();
};

Le tableau suivant, le rendement de l'erreur:

A a;      //destructor undefined

La mise en œuvre peut être en ligne, dans la définition de la classe elle-même:

struct A
{ 
    ~A() {}
};

ou à l'extérieur:

A::~A() {}

Si la mise en œuvre est en dehors de la définition de la classe, mais dans un en-tête, les méthodes doivent être marqués comme inline pour prévenir une définition de plusieurs.

Tous utilisé des méthodes membres doivent être définis si utilisé.

Une erreur commune est d'oublier de qualifier le nom:

struct A
{
   void foo();
};

void foo() {}

int main()
{
   A a;
   a.foo();
}

La définition devrait être

void A::foo() {}

static de membres de données doit être défini en dehors de la classe dans une seule unité de traduction:

struct X
{
    static int x;
};
int main()
{
    int x = X::x;
}
//int X::x; //uncomment this line to define X::x

Un initialiseur peuvent être fournis pour un static const membre de données intégrales ou de type énumération dans la définition de la classe; toutefois, rll-l'usage de ce membre aura toujours besoin d'un espace de noms définition de la portée, comme décrit ci-dessus. C++11 permet d'initialisation à l'intérieur de la classe pour tous les static const de données des membres.

109voto

Luchian Grigore Points 136646

L'échec de lier des bibliothèques appropriées/fichiers d'objet ou de compiler des fichiers de mise en œuvre

Généralement, chaque unité de traduction va générer un fichier de l'objet qui contient les définitions des symboles définis dans cette unité de traduction. À l'utilisation de ces symboles, vous avez un lien à l'encontre de ces fichiers objets.

En vertu de la gcc, vous devez spécifier tous les fichiers objets qui doivent être reliés à la ligne de commande, ou de compiler les fichiers de mise en œuvre ensemble.

g++ -o test objectFile1.o objectFile2.o -lLibraryName

Pour XCode: Ajouter l'en-Tête Utilisateur Chemins de Recherche -> ajouter le Chemin de Recherche des bibliothèques -> glisser et déposer l'effectif de référence de la bibliothèque dans le dossier du projet.

En vertu de MSVS, les fichiers ajoutés à un projet automatiquement leurs fichiers objets liés ensemble, et un lib le fichier généré (à usage commun). L'utilisation des symboles dans un projet distinct, vous feriez besoin d'inclure l' lib fichiers dans les paramètres du projet. Ceci est fait dans l'éditeur de liens de la section propriétés du projet, en Input -> Additional Dependencies. (le chemin d'accès à l' lib le fichier doit être ajoutée en Linker -> General -> Additional Library Directories) Lors de l'utilisation d'une bibliothèque tierce, qui est fourni avec un lib le fichier, à défaut de le faire est généralement le résultat dans l'erreur.

Il peut aussi arriver que vous oubliez d'ajouter le fichier à la compilation, auquel cas le fichier de l'objet ne seront pas générées. Dans gcc , vous devez ajouter les fichiers à la ligne de commande. Dans MSVSl'ajout d' le fichier pour le projet permettra de faire compiler automatiquement.

Dans la programmation Windows, le signe révélateur que vous n'avez pas de lien nécessaire de la bibliothèque, c'est que le nom du symbole non commence avec __imp_. Recherchez le nom de la fonction dans la documentation, et il faut dire que la bibliothèque, vous devez utiliser. Par exemple, MSDN place les informations dans une boîte au fond de chaque fonction dans une section appelée "Bibliothèque".

97voto

Luchian Grigore Points 136646

Déclarée mais n'a pas définir une variable ou une fonction.

Typique de la déclaration de la variable est

extern int x;

Comme ce n'est qu'une déclaration, une définition unique est nécessaire. Une définition correspondante serait:

int x;

Pour exemple, le code suivant génère une erreur:

extern int x;
int main()
{
    x = 0;
}
//int x; // uncomment this line for successful definition

Des observations semblables s'appliquent à des fonctions. La déclaration d'une fonction sans la définir conduit à l'erreur:

void foo(); // declaration only
int main()
{
   foo();
}
//void foo() {} //uncomment this line for successful definition

Veillez à ce que la fonction que vous mettre en œuvre correspond exactement à celui que vous avez déclaré. Par exemple, vous avez peut-être incompatibles cv-qualificatifs:

void foo(int& x);
int main()
{
   int x;
   foo(x);
}
void foo(const int& x) {} //different function, doesn't provide a definition
                          //for void foo(int& x)

D'autres exemples de décalages inclure

  • Fonction/variable déclarée dans un espace de noms, définie dans un autre.
  • Fonction/variable déclarée comme membre de la classe, définie comme un phénomène global (ou vice versa).
  • La fonction de type de retour, le numéro de paramètre et les types, et de la convention d'appel n'ont pas tous exactement d'accord.

Le message d'erreur du compilateur sera souvent vous donner l'intégralité de la déclaration de la variable ou de la fonction qui a été déclaré, mais jamais défini. Comparer étroitement à la définition que vous avez fournis. Assurez-vous que tous les détails de matchs.

68voto

Luchian Grigore Points 136646

Les symboles ont été définies dans un programme C et utilisé dans du code C++.

La fonction (ou une variable) void foo() a été défini dans un programme C et que vous essayez de l'utiliser dans un programme en C++:

void foo();
int main()
{
    foo();
}

Le C++ linker attend des noms de déformation, de sorte que vous avez à déclarer la fonction:

extern "C" void foo();
int main()
{
    foo();
}

De manière équivalente, au lieu d'être définies dans un programme C, la fonction (ou une variable) void foo() a été défini en C++, mais avec une liaison C:

extern "C" void foo();

et vous essayez de l'utiliser dans un programme en C++ en C++, la liaison.

Si une bibliothèque entière est inclus dans un fichier d'en-tête (et a été compilé en code C); l'inclure devra être comme suit;

extern "C" {
    #include "cheader.h"
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X