什么是未定义的引用/未解析的外部符号错误,我该如何解决它?
什么是未定义的引用/未解析的外部符号错误? 什么是常见原因以及如何修复/防止它们?
随意编辑/添加自己的。
编译一个C ++程序需要几个步骤,如2.2所指出的(授予Keith Thompson作为参考):
翻译的语法规则中的优先顺序由以下几个阶段规定[见脚注]。
[脚注]实现必须表现得好像这些分离的阶段一样,尽管在实践中不同的阶段可能会被折叠在一起。
指定的错误发生在编译的最后阶段,通常称为链接。 它基本上意味着你编译了一堆实现文件到目标文件或库中,现在你想让它们一起工作。
假设你在a.cpp
定义了符号a
。 现在, b.cpp
声明该符号并使用它。 在链接之前,它只是假定那个符号是在某个地方定义的,但它并不关心它在哪里。 链接阶段负责找到符号,并将其正确地链接到b.cpp
(实际上是指使用它的对象或库)。
如果您使用Microsoft Visual Studio,您会看到项目生成.lib
文件。 这些包含一个导出符号表和一个导入符号表。 导入的符号是针对链接的库进行解析的,导出的符号是为使用该.lib
(如果有的话)的库提供的。
其他编译器/平台也有类似的机制。
常见错误消息是error LNK2001
error LNK1120
error LNK2019
, Microsoft Visual Studio error LNK2019
和undefined reference to
的GCC symbolName undefined reference to
。
代码:
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;
}
将与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
和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
常见原因包括:
#pragma
(Microsoft Visual Studio)时不要使用.lib扩展名 UNICODE
定义不一致 班级成员:
一个纯粹的virtual
析构函数需要一个实现。
声明纯粹的析构函数仍然需要您定义它(与常规函数不同):
struct X
{
virtual ~X() = 0;
};
struct Y : X
{
~Y() {}
};
int main()
{
Y y;
}
//X::~X(){} //uncomment this line for successful definition
发生这种情况是因为在隐式地销毁对象时调用基类析构函数,所以需要定义。
virtual
方法必须被实现或定义为纯粹的。
这与没有定义的非virtual
方法类似,但增加了推理:纯声明会生成虚拟vtable,并且可能会在不使用函数的情况下获得链接器错误:
struct X
{
virtual void foo();
};
struct Y : X
{
void foo() {}
};
int main()
{
Y y; //linker error although there was no call to X::foo
}
为此,将X::foo()
声明为纯粹的:
struct X
{
virtual void foo() = 0;
};
非virtual
类成员
即使不明确使用,也需要定义一些成员:
struct A
{
~A();
};
以下将产生错误:
A a; //destructor undefined
该实现可以内联在类定义本身中:
struct A
{
~A() {}
};
或外面:
A::~A() {}
如果实现在类定义之外,但在标题中,则方法必须标记为inline
以防止多重定义。
如果使用所有使用的成员方法,则需要定义。
一个常见的错误是忘记限定名称:
struct A
{
void foo();
};
void foo() {}
int main()
{
A a;
a.foo();
}
定义应该是
void A::foo() {}
static
数据成员必须在单个翻译单元的类外定义:
struct X
{
static int x;
};
int main()
{
int x = X::x;
}
//int X::x; //uncomment this line to define X::x
可以为类定义中的整型或枚举类型的static
const
数据成员提供初始化程序; 然而,这个成员的odr使用仍然需要一个名称空间作用域定义,如上所述。 C ++ 11允许在类内为所有static const
数据成员进行初始化。
未能链接到适当的库/对象文件或编译实现文件
通常,每个翻译单元将生成一个包含该翻译单元中定义的符号定义的目标文件。 要使用这些符号,您必须链接到这些目标文件。
在gcc下,您可以指定要在命令行中链接在一起的所有对象文件,或者一起编译实现文件。
g++ -o test objectFile1.o objectFile2.o -lLibraryName
这里的libraryName
只是库的名字,没有特定于平台的添加。 因此,例如在Linux库文件通常被称为libfoo.so
但你只能写-lfoo
。 在Windows上,相同的文件可能被称为foo.lib
,但是你会使用相同的参数。 您可能需要使用-L‹directory›
添加可以找到这些文件的-L‹directory›
。 确保在-l
或-L
之后不写入空格。
对于XCode :添加用户头搜索路径 - >添加库搜索路径 - >将实际库引用拖放到项目文件夹中。
在MSVS下 ,添加到项目的文件自动将它们的目标文件链接在一起,并生成一个lib
文件(常用)。 要在单独项目中使用这些符号,您需要将lib
文件包含在项目设置中。 这是在项目属性的链接器部分的Input -> Additional Dependencies
。 ( lib
文件的路径应该添加到Linker -> General -> Additional Library Directories
)使用lib
文件提供的第三方库时,如果不这样做通常会导致错误。
它也可能发生,你忘记将文件添加到编译,在这种情况下,将不会生成目标文件。 在gcc中,你可以将这些文件添加到命令行中。 在MSVS中,将文件添加到项目中会自动进行编译(尽管可以手动将文件从构建中单独排除)。
在Windows编程中,未链接必要库的迹象表明,未解析符号的名称以__imp_
。 在文档中查找该函数的名称,并且应该说明您需要使用哪个库。 例如,MSDN将信息放在每个函数底部的一个框中,称为“库”。
上一篇: What is an undefined reference/unresolved external symbol error and how do I fix it?