程序中的 undefined reference 錯誤
在实际编译代码的过程中,我们经常会遇到"undefined reference to"的问题,简单的可以轻易地解决,但有些却隐藏得很深,需要花费大量的时间去排查。工作中遇到了各色各样类似的问题,按照以下几种可能出现的状况去排查,可有利于理清头绪,从而迅速解决问题[1]。在[1]中,作者介绍了一下几种情况,我在自己的电脑上大部分都进行过测试,另外本文还着重测试了其中的一个问题
链接时缺失了相关目标文件
首先编写如下的测试代码:
// test.h
#ifndef __TEST_H__
#define __TEST_H__
void TestUndefined();
#endif
// test.c
#include
#include
void TestUndefined()
{
printf("just test it\n");
}
// main.c
#include"test.h"
intmain(int argc, char **argv)
{
TestUndefined();
return0;
}
通过以下的命令,我们将会得到两个.o文件。
$ gcc -c test.c
$ gcc –c main.c
随后,我们将main.o这个文件,编译成可执行文件。
$ gcc -o main main.o
main.o: In function `main':
main.c:(.text+0xa): undefined reference to `TestUndefined'
collect2: error: ld returned 1 exit status
编译时报错了,这是最典型的undefined reference错误,因为在链接时发现找不到某个函数的实现文件。如果按下面这种方式链接就正确了。
$ gcc -o main main.o test.o
当然,也可以按照如下的命令编译,这样就可以一步到位。
$ gcc -o main main.c test.c
链接时缺少相关的库文件
我们把第一个示例中的test.c编译成静态库。
$ gcc -c test.c
$ ar -rc test.a test.o
接着编译可执行文件,使用如下命令:
$ gcc -o main main.c
/tmp/ccxuAS7S.o: In function `main':
main.c:(.text+0xa): undefined reference to `TestUndefined'
collect2: error: ld returned 1 exit status
TestUndefined() 函数的实现文件,TestUndefined()函数的实现在test.a这个静态库中,故在链接的时候需要在其后加入test.a这个库,链接命令修改为如下形式即可。
$ gcc -o main main.c test.a
链接的库文件中又使用了另一个库文件
// func.h
#ifndef __FUNC_H__
#define __FUNC_H__
void func();
#endif
// func.c
#include
void func()
{
printf("call it\n");
}
// test.h
#ifndef __TEST_H__
#define __TEST_H__
void TestUndefined();
#endif
// test.c
#include "stdio.h"
#include "func.h"
void TestUndefined()
{
printf("just test it\n");
func();
}
// main.c
#include "test.h"
int main(int argc, char **argv)
{
TestUndefined();
return0;
}
我们先对fun.c和test.c进行编译,生成.o文件。
$ gcc -cfunc.c
$gcc -ctest.c
然后,将test.c和func.c各自打包成为静态库文件。
$ ar –rc func.a func.o
$ ar –rc test.a test.o
这时将main.c编译为可执行程序,由于main.TestUndefined()的调用,因此,应该在链接时将test.a作为我们的库文件,链接命令如下。
$ gcc -o main main.c test.a
test.o: In function `TestUndefined':
test.c:(.text+0x16): undefined reference to `func'
collect2: error: ld returned 1 exit status
就是说,链接的时候发现test.a调用了func()函数,找不到对应的实现,我们还需要将test.a所引用到的库文件也加进来才能成功链接,因此命令如下。
$ gcc -o main main.c test.a func.a
同样,如果我们的库或者程序中引用了第三方库(如pthread.a)则在链接的时候需要给出第三方库的路径和库文件,否则就会得到undefined reference的错误。
多个库文件链接顺序问题
这种问题非常隐蔽,不仔细研究,可能会感到非常地莫名其妙。以第三个示例为测试代码,把链接库的顺序换一下,如下所示:
$ gcc -o main main.c func.a test.a
test.a(test.o): In function `TestUndefined':
test.c:(.text+0x16): undefined reference to `func'
collect2: error: ld returned 1 exit status
因此,在链接命令中给出所依赖的库时,需要注意库之间的依赖顺序,依赖其他库的库一定要放到被依赖库的前面,这样才能真正避免undefined reference的错误,完成编译链接。
在c++代码中链接c语言的库
代码同示例一的代码一样,只是把main.c更改成了main.cpp。编译test.c,并打包为静态库。
$ gcc -c test.c
$ ar -rc test.a test.o
编译可执行文件,用如下命令:
$ g++ -o main main.cpp test.a
Undefined symbols for architecture x86_64:
"test()", referenced from:
_main in main-7d7fde.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed withexit code 1 (use -v to see invocation)
原因就是main.cpp为c++代码,调用了c语言库的函数,因此链接的时候找不到,解决方法是在相关文件添加一个extern "C"的声明即可,例如修改test.h文件。
// test.h
#ifndef __TEST_H__
#define __TEST_H__
#ifdef __cplusplus
extern"C" {
#endif
void test();
#ifdef __cplusplus
}
#endif
#endif
gcc 和 g++ 编译
//func2.c 和func1.cpp
#include <stdio.h>
int max(int x, int y)
{
return (x > y) ? x : y;
}
int main()
{
int max_num = max(10,20);
return 0;
}
func2.c 采用gcc 编译
.file "func2.c"
.text
.globl max
.type max, @function
max:
...
func1.cpp 采用gcc 编译
.file "func1.cpp"
.text
.globl _Z3maxii
.type _Z3maxii, @function
_Z3maxii:
...
func2.c 采用g++ 编译
.file "func2.c"
.text
.globl _Z3maxii
.type _Z3maxii, @function
_Z3maxii:
...
func1.cpp 采用g++ 编译
.file "func1.cpp"
.text
.globl _Z3maxii
.type _Z3maxii, @function
_Z3maxii:
...
另外:加入extern "C"的func2.c
#include <stdio.h>
#ifdef __cplusplus
extern "C"{
#endif
int max(int x, int y)
{
return (x > y) ? x : y;
}
#ifdef __cplusplus
}
#endif
int main() {
int max_num = max(10,20);
return 0;
}
__func2.c__采用g++ 编译
.file "func2.c"
.text
.globl max
.type max, @function
max:
...
因此可以看到 extern “C” 用于 C / C++ 混合编程,C函数不能进行函数重载,而C++可以,因此GCC 和G++在编译的时候会出现不同的名字,倘若在C++的程序中使用了一部分C的函数库,很有可能会出现某些错误,其中可能就有undefined reference的错误
参考文献:
[1]. txgcwm. “undefined reference to” 问题汇总及解决方法. https://segmentfault.com/a/1190000006049907?utm_source=tuicool&utm_medium=referral