什么是未定义的引用 / 未解析的外部符号错误? 如何修复它?

What are undefined reference/unresolved external symbol errors? What are common causes and how to fix/prevent them?

Feel free to edit/add your own.

转载于:https://stackoverflow.com/questions/12573816/what-is-an-undefined-reference-unresolved-external-symbol-error-and-how-do-i-fix

csdnceshi73
喵-见缝插针 I had an error where my project was compiled as x64 project. and I've used a Library that was compiled as x86. I've recompiled the library as x64 and it solved it.
大约 3 年之前 回复
csdnceshi76
斗士狗 see stackoverflow.com/a/12574407/673730 - A common mistake is forgetting to qualify the name :)
3 年多之前 回复
csdnceshi51
旧行李 This was exactly my problem. Thank you! I am new to cpp, but as far as I can tell, I was having the exact problem that Ben Voigt says was quite rare. I think your solution would make a great answer.
3 年多之前 回复
csdnceshi77
狐狸.fox If this happens to you with a Qt signal, you most likely forgot the Q_OBJECT macro.
4 年多之前 回复
csdnceshi53
Lotus@ While that does happen, the programmer usually notices that he has no this pointer and no access to class members. It's quite rare to complete compilation and only fail during linking, when a non-static member function is missing its qualified-name.
接近 5 年之前 回复
csdnceshi80
胖鸭 Pretty common mistake is that you define a function as a standalone and forget the class selector (e.g. A::) in your .cpp file: You do this (wrong): void myFunc() { /* do stuff */ } Instead of this (right): void A::myFunc() { /* do stuff */ }
接近 5 年之前 回复
csdnceshi66
必承其重 | 欲带皇冠 'feel free to add an answer' I preferred to add the relevant link (IMHO) your primary answer, if you'd like to permit.
接近 6 年之前 回复
csdnceshi66
必承其重 | 欲带皇冠 I've been marking this question to be a possible dupe of this one. But after going through all of your (brilliant) answers, I can't see this case covered here. I'm aware it's specific about how an IDE sets up the project type and it's linkage dependencies. But that's a such frequently asked question I think it would be worth covered (maybe just with a link to another appropriate dupe) here. If it is already, and I just didn't spot it, forget about this request/comment.
接近 6 年之前 回复
csdnceshi59
ℙℕℤℝ One thing to consider adding is how to deal with "undefined vtable" and "undefined typeinfo" errors in particular (since they are less obvious than undefined functions or variables).
6 年多之前 回复

29个回答

Compiling a C++ program takes place in several steps, as specified by 2.2 (credits to Keith Thompson for the reference):

The precedence among the syntax rules of translation is specified by the following phases [see footnote].

  1. Physical source file characters are mapped, in an implementation-defined manner, to the basic source character set (introducing new-line characters for end-of-line indicators) if necessary. [SNIP]
  2. Each instance of a backslash character (\) immediately followed by a new-line character is deleted, splicing physical source lines to form logical source lines. [SNIP]
  3. The source file is decomposed into preprocessing tokens (2.5) and sequences of white-space characters (including comments). [SNIP]
  4. Preprocessing directives are executed, macro invocations are expanded, and _Pragma unary operator expressions are executed. [SNIP]
  5. Each source character set member in a character literal or a string literal, as well as each escape sequence and universal-character-name in a character literal or a non-raw string literal, is converted to the corresponding member of the execution character set; [SNIP]
  6. Adjacent string literal tokens are concatenated.
  7. White-space characters separating tokens are no longer significant. Each preprocessing token is converted into a token. (2.7). The resulting tokens are syntactically and semantically analyzed and translated as a translation unit. [SNIP]
  8. Translated translation units and instantiation units are combined as follows: [SNIP]
  9. All external entity references are resolved. Library components are linked to satisfy external references to entities not defined in the current translation. All such translator output is collected into a program image which contains information needed for execution in its execution environment. (emphasis mine)

[footnote] Implementations must behave as if these separate phases occur, although in practice different phases might be folded together.

The specified errors occur during this last stage of compilation, most commonly referred to as linking. It basically means that you compiled a bunch of implementation files into object files or libraries and now you want to get them to work together.

Say you defined symbol a in a.cpp. Now, b.cpp declared that symbol and used it. Before linking, it simply assumes that that symbol was defined somewhere, but it doesn't yet care where. The linking phase is responsible for finding the symbol and correctly linking it to b.cpp (well, actually to the object or library that uses it).

If you're using Microsoft Visual Studio, you'll see that projects generate .lib files. These contain a table of exported symbols, and a table of imported symbols. The imported symbols are resolved against the libraries you link against, and the exported symbols are provided for the libraries that use that .lib (if any).

Similar mechanisms exist for other compilers/ platforms.

Common error messages are error LNK2001, error LNK1120, error LNK2019 for Microsoft Visual Studio and undefined reference to symbolName for 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;
}

will generate the following errors with 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

and similar errors with 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

Common causes include:

csdnceshi59
ℙℕℤℝ it would be nice if you add the correct, fixing the above errors
大约 2 年之前 回复
weixin_41568127
?yb? Use gcc? MinGW to be more precise.
3 年多之前 回复
csdnceshi78
程序go And how to define where is my case?! stackoverflow.com/questions/32915615/…
4 年多之前 回复
csdnceshi50
三生石@ David Drysdale wrote a great article about how linkers work: Beginner's Guide to Linkers. Given the topic of this question, I thought it might prove useful.
接近 5 年之前 回复
csdnceshi79
python小菜 Personally, I think the MS linker error messages are just as readable as the GCC errors. They also have the advantage of including both the mangled and unmangled names for the unresolved external. Having the mangled name can be helpful when you need to look at the libraries or object files directly to see what the problem might be (for example, a calling convention mismatch). Also, I'm not sure what version of MSVC produced the errors here, but newer versions include the name (both mangled and unmangled) of the function referring to the unresolved external symbol.
大约 6 年之前 回复
csdnceshi51
旧行李 If only. I think you can modify output using this, but I haven't tried it.
大约 6 年之前 回复
weixin_41568126
乱世@小熊 is there a way to get better VS linker errors? To get it look more like gcc ones, for example.
大约 6 年之前 回复

Class members:

A pure virtual destructor needs an implementation.

Declaring a destructor pure still requires you to define it (unlike a regular function):

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

This happens because base class destructors are called when the object is destroyed implicitly, so a definition is required.

virtual methods must either be implemented or defined as pure.

This is similar to non-virtual methods with no definition, with the added reasoning that the pure declaration generates a dummy vtable and you might get the linker error without using the function:

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

For this to work, declare X::foo() as pure:

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

Non-virtual class members

Some members need to be defined even if not used explicitly:

struct A
{ 
    ~A();
};

The following would yield the error:

A a;      //destructor undefined

The implementation can be inline, in the class definition itself:

struct A
{ 
    ~A() {}
};

or outside:

A::~A() {}

If the implementation is outside the class definition, but in a header, the methods have to be marked as inline to prevent a multiple definition.

All used member methods need to be defined if used.

A common mistake is forgetting to qualify the name:

struct A
{
   void foo();
};

void foo() {}

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

The definition should be

void A::foo() {}

static data members must be defined outside the class in a single translation unit:

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

An initializer can be provided for a static const data member of integral or enumeration type within the class definition; however, odr-use of this member will still require a namespace scope definition as described above. C++11 allows initialization inside the class for all static const data members.

csdnceshi76
斗士狗 Just thought you might want to stress that doing both is possible, and the dtor is not actually an exception. (it's not obvious from your wording at first glance.)
5 年多之前 回复
weixin_41568196
撒拉嘿哟木头 see "A virtual function declared in a class shall be defined, or declared pure (10.4) in that class, or both; but no diagnostic is required" (10.3 Virtual functions) - unless this was changed in C++14
5 年多之前 回复
weixin_41568196
撒拉嘿哟木头 "need" vs. "should". Pedantically, non-pure virtual functions need be defined (although, as mentioned, some compilers won't complain until you call them, but some will). I don't think I said you can't define pure virtuals.
5 年多之前 回复
csdnceshi76
斗士狗 No need to define any non-virtual function you never use. Also, no need to define any virtual function, if you never construct an object of the class, nor call it from a derived class you actually instantiate. In addition, all pure virtual functions can be defined.
5 年多之前 回复
weixin_41568174
from.. Not sure this part - C++11 allows initialization inside the class for all static const data members is correct. [class.static.data]/3 says you need to mark the static data members constexpr if they're not of integral or enumeration type.
5 年多之前 回复
csdnceshi72
谁还没个明天 The last line of this answer is incorrect, an in-class declaration is never a definition. (Definitions aren't needed for static members that aren't odr-used, which is common for integral compile-time constants)
5 年多之前 回复

Failure to link against appropriate libraries/object files or compile implementation files

Commonly, each translation unit will generate an object file that contains the definitions of the symbols defined in that translation unit. To use those symbols, you have to link against those object files.

Under gcc you would specify all object files that are to be linked together in the command line, or compile the implementation files together.

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

The libraryName here is just the bare name of the library, without platform-specific additions. So e.g. on Linux library files are usually called libfoo.so but you'd only write -lfoo. On Windows that same file might be called foo.lib, but you'd use the same argument. You might have to add the directory where those files can be found using -L‹directory›. Make sure to not write a space after -l or -L.

For XCode: Add the User Header Search Paths -> add the Library Search Path -> drag and drop the actual library reference into the project folder.

Under MSVS, files added to a project automatically have their object files linked together and a lib file would be generated (in common usage). To use the symbols in a separate project, you'd need to include the lib files in the project settings. This is done in the Linker section of the project properties, in Input -> Additional Dependencies. (the path to the lib file should be added in Linker -> General -> Additional Library Directories) When using a third-party library that is provided with a lib file, failure to do so usually results in the error.

It can also happen that you forget to add the file to the compilation, in which case the object file won't be generated. In gcc you'd add the files to the command line. In MSVS adding the file to the project will make it compile it automatically (albeit files can, manually, be individually excluded from the build).

In Windows programming, the tell-tale sign that you did not link a necessary library is that the name of the unresolved symbol begins with __imp_. Look up the name of the function in the documentation, and it should say which library you need to use. For example, MSDN puts the information in a box at the bottom of each function in a section called "Library".

Declared but did not define a variable or function.

A typical variable declaration is

extern int x;

As this is only a declaration, a single definition is needed. A corresponding definition would be:

int x;

For example, the following would generate an error:

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

Similar remarks apply to functions. Declaring a function without defining it leads to the error:

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

Be careful that the function you implement exactly matches the one you declared. For example, you may have mismatched cv-qualifiers:

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)

Other examples of mismatches include

  • Function/variable declared in one namespace, defined in another.
  • Function/variable declared as class member, defined as global (or vice versa).
  • Function return type, parameter number and types, and calling convention do not all exactly agree.

The error message from the compiler will often give you the full declaration of the variable or function that was declared but never defined. Compare it closely to the definition you provided. Make sure every detail matches.

weixin_41568184
叼花硬汉 In VS, cpp files matching those in header #includes not added to the source directory also falls under the category of missing definitions.
接近 2 年之前 回复
csdnceshi74
7*4 already covered by stackoverflow.com/a/12574420/673730
5 年多之前 回复
csdnceshi69
YaoRaoLov People do ask about unresolved externals due to misspelled names, so it's not entirely obvious. (Not sure what you're referring to about parameter names. Parameter names are not part of the type.)
6 年多之前 回复
csdnceshi74
7*4 I left out function name misspell as it's fairly obvious. As for parameter names - what?
6 年多之前 回复

The order in which interdependent linked libraries are specified is wrong.

The order in which libraries are linked DOES matter if the libraries depend on each other. In general, if library A depends on library B, then libA MUST appear before libB in the linker flags.

For example:

// B.h
#ifndef B_H
#define B_H

struct B {
    B(int);
    int x;
};

#endif

// B.cpp
#include "B.h"
B::B(int xx) : x(xx) {}

// A.h
#include "B.h"

struct A {
    A(int x);
    B b;
};

// A.cpp
#include "A.h"

A::A(int x) : b(x) {}

// main.cpp
#include "A.h"

int main() {
    A a(5);
    return 0;
};

Create the libraries:

$ g++ -c A.cpp
$ g++ -c B.cpp
$ ar rvs libA.a A.o 
ar: creating libA.a
a - A.o
$ ar rvs libB.a B.o 
ar: creating libB.a
a - B.o

Compile:

$ g++ main.cpp -L. -lB -lA
./libA.a(A.o): In function `A::A(int)':
A.cpp:(.text+0x1c): undefined reference to `B::B(int)'
collect2: error: ld returned 1 exit status
$ g++ main.cpp -L. -lA -lB
$ ./a.out

So to repeat again, the order DOES matter!

csdnceshi68
local-host -Wl,--start-group .....-Wl,--end-group solves this problem.
大约 2 年之前 回复
csdnceshi66
必承其重 | 欲带皇冠 I curious fact is that in my case I had one object file that depends on a shared library. I had to modify the Makefile and put the library AFTER the object with gcc 4.8.4 on Debian. On Centos 6.5 with gcc 4.4 the Makefile worked with no problem.
3 年多之前 回复

what is an "undefined reference/unresolved external symbol"

I'll try to explain what is an "undefined reference/unresolved external symbol".

note: i use g++ and Linux and all examples is for it

For example we have some code

// src1.cpp
void print();

static int local_var_name; // 'static' makes variable not visible for other modules
int global_var_name = 123;

int main()
{
    print();
    return 0;
}

and

// src2.cpp
extern "C" int printf (const char*, ...);

extern int global_var_name;
//extern int local_var_name;

void print ()
{
    // printf("%d%d\n", global_var_name, local_var_name);
    printf("%d\n", global_var_name);
}

Make object files

$ g++ -c src1.cpp -o src1.o
$ g++ -c src2.cpp -o src2.o

After the assembler phase we have an object file, which contains any symbols to export. Look at the symbols

$ readelf --symbols src1.o
  Num:    Value          Size Type    Bind   Vis      Ndx Name
     5: 0000000000000000     4 OBJECT  LOCAL  DEFAULT    4 _ZL14local_var_name # [1]
     9: 0000000000000000     4 OBJECT  GLOBAL DEFAULT    3 global_var_name     # [2]

I've rejected some lines from output, because they do not matter

So, we see follow symbols to export.

[1] - this is our static (local) variable (important - Bind has a type "LOCAL")
[2] - this is our global variable

src2.cpp exports nothing and we have seen no its symbols

Link our object files

$ g++ src1.o src2.o -o prog

and run it

$ ./prog
123

Linker sees exported symbols and links it. Now we try to uncomment lines in src2.cpp like here

// src2.cpp
extern "C" int printf (const char*, ...);

extern int global_var_name;
extern int local_var_name;

void print ()
{
    printf("%d%d\n", global_var_name, local_var_name);
}

and rebuild an object file

$ g++ -c src2.cpp -o src2.o

OK (no errors), because we only build object file, linking is not done yet. Try to link

$ g++ src1.o src2.o -o prog
src2.o: In function `print()':
src2.cpp:(.text+0x6): undefined reference to `local_var_name'
collect2: error: ld returned 1 exit status

It has happened because our local_var_name is static, i.e. it is not visible for other modules. Now more deeply. Get the translation phase output

$ g++ -S src1.cpp -o src1.s

// src1.s
look src1.s

    .file   "src1.cpp"
    .local  _ZL14local_var_name
    .comm   _ZL14local_var_name,4,4
    .globl  global_var_name
    .data
    .align 4
    .type   global_var_name, @object
    .size   global_var_name, 4
global_var_name:
    .long   123
    .text
    .globl  main
    .type   main, @function
main:
; assembler code, not interesting for us
.LFE0:
    .size   main, .-main
    .ident  "GCC: (Ubuntu 4.8.2-19ubuntu1) 4.8.2"
    .section    .note.GNU-stack,"",@progbits

So, we've seen there is no label for local_var_name, that's why linker hasn't found it. But we are hackers :) and we can fix it. Open src1.s in your text editor and change

.local  _ZL14local_var_name
.comm   _ZL14local_var_name,4,4

to

    .globl  local_var_name
    .data
    .align 4
    .type   local_var_name, @object
    .size   local_var_name, 4
local_var_name:
    .long   456789

i.e. you should have like below

    .file   "src1.cpp"
    .globl  local_var_name
    .data
    .align 4
    .type   local_var_name, @object
    .size   local_var_name, 4
local_var_name:
    .long   456789
    .globl  global_var_name
    .align 4
    .type   global_var_name, @object
    .size   global_var_name, 4
global_var_name:
    .long   123
    .text
    .globl  main
    .type   main, @function
main:
; ...

we have changed the visibility of local_var_name and set its value to 456789. Try to build an object file from it

$ g++ -c src1.s -o src2.o

ok, see readelf output (symbols)

$ readelf --symbols src1.o
8: 0000000000000000     4 OBJECT  GLOBAL DEFAULT    3 local_var_name

now local_var_name has Bind GLOBAL (was LOCAL)

link

$ g++ src1.o src2.o -o prog

and run it

$ ./prog 
123456789

ok, we hack it :)

So, as a result - an "undefined reference/unresolved external symbol error" happens when the linker cannot find global symbols in the object files.

Symbols were defined in a C program and used in C++ code.

The function (or variable) void foo() was defined in a C program and you attempt to use it in a C++ program:

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

The C++ linker expects names to be mangled, so you have to declare the function as:

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

Equivalently, instead of being defined in a C program, the function (or variable) void foo() was defined in C++ but with C linkage:

extern "C" void foo();

and you attempt to use it in a C++ program with C++ linkage.

If an entire library is included in a header file (and was compiled as C code); the include will need to be as follows;

extern "C" {
    #include "cheader.h"
}
csdnceshi69
YaoRaoLov As in the above comment, the 'Creating Mixed-Language Headers' section here helped: oracle.com/technetwork/articles/servers-storage-dev/…
大约 3 年之前 回复
csdnceshi51
旧行李 Or conversely, If you develop a C library, a nice rule is to protect the header file(s) by surrounding all exported declarations with #ifdef __cplusplus [\n] extern"C" { [\n] #endif and #ifdef __cplusplus [\n] } [\n] #endif ([\n] being real carriage return but I can't write this properly in comment).
4 年多之前 回复

If all else fails, recompile.

I was recently able to get rid of an unresolved external error in Visual Studio 2012 just by recompiling the offending file. When I re-built, the error went away.

This usually happens when two (or more) libraries have a cyclic dependency. Library A attempts to use symbols in B.lib and library B attempts to use symbols from A.lib. Neither exist to start off with. When you attempt to compile A, the link step will fail because it can't find B.lib. A.lib will be generated, but no dll. You then compile B, which will succeed and generate B.lib. Re-compiling A will now work because B.lib is now found.

csdnceshi53
Lotus@ I expanded on your answer and linked in in the main one. Thanks.
大约 6 年之前 回复
csdnceshi53
Lotus@ Correct - this happens when libraries have a cyclic dependency.
大约 6 年之前 回复

Incorrectly importing/exporting methods/classes across modules/dll (compiler specific).

MSVS requires you to specify which symbols to export and import using __declspec(dllexport) and __declspec(dllimport).

This dual functionality is usually obtained through the use of a macro:

#ifdef THIS_MODULE
#define DLLIMPEXP __declspec(dllexport)
#else
#define DLLIMPEXP __declspec(dllimport)
#endif

The macro THIS_MODULE would only be defined in the module that exports the function. That way, the declaration:

DLLIMPEXP void foo();

expands to

__declspec(dllexport) void foo();

and tells the compiler to export the function, as the current module contains its definition. When including the declaration in a different module, it would expand to

__declspec(dllimport) void foo();

and tells the compiler that the definition is in one of the libraries you linked against (also see 1)).

You can similary import/export classes:

class DLLIMPEXP X
{
};
csdnceshi80
胖鸭 I haven't used .def files in ages. Feel free to add an answer or edit this one.
大约 7 年之前 回复
csdnceshi72
谁还没个明天 To be complete, this answer should mention GCC's visibility and Windows' .def files, as these also influence the symbol name and presence.
大约 7 年之前 回复

Template implementations not visible.

Unspecialized templates must have their definitions visible to all translation units that use them. That means you can't separate the definition of a template to an implementation file. If you must separate the implementation, the usual workaround is to have an impl file which you include at the end of the header that declares the template. A common situation is:

template<class T>
struct X
{
    void foo();
};

int main()
{
    X<int> x;
    x.foo();
}

//differentImplementationFile.cpp
template<class T>
void X<T>::foo()
{
}

To fix this, you must move the definition of X::foo to the header file or some place visible to the translation unit that uses it.

Specialized templates can be implemented in an implementation file and the implementation doesn't have to be visible, but the specialization must be previously declared.

For further explanation and another possible solution (explicit instantiation) see this question and answer.

weixin_41568126
乱世@小熊 Further information for "templates must be defined in the header" can be found in stackoverflow.com/questions/495021
5 年多之前 回复
共29条数据 1 3 尾页
Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
立即提问