“undefined reference to“ 问题汇总及解决方法 ——非常非常好的一篇文章

“undefined reference to“ 问题汇总及解决方法 ——非常非常好的一篇文章转载地址:https://segmentfault.com/a/1190000006049907?utm_source=tuicool&utm_medium=referral在实际编译代码的过程中,我们经常会遇到”undefinedreferenceto”的问题,简单的可以轻易地解决,但有些却隐藏得很深,需要花费大量的时间去排查。工作中遇到了各色各样类似的问题,按照以下几

大家好,又见面了,我是你们的朋友全栈君。

在实际编译代码的过程中,我们经常会遇到"undefined reference to"的问题,简单的可以轻易地解决,但有些却隐藏得很深,需要花费大量的时间去排查。工作中遇到了各色各样类似的问题,按照以下几种可能出现的状况去排查,可有利于理清头绪,从而迅速解决问题。

链接时缺失了相关目标文件

首先编写如下的测试代码:


// test.h #ifndef __TEST_H__ #define __TEST_H__ void test(); #endif // test.c #include <string.h> #include <stdio.h> void test() { printf("just test it\n"); } // main.c #include "test.h" int main(int argc, char **argv) { test(); return 0; }

通过以下的命令,我们将会得到两个.o文件。

$ gcc -c test.c  
$ gcc –c main.c 

随后,我们将main.o这个文件,编译成可执行文件。

$ gcc -o main main.o
Undefined symbols for architecture x86_64:
  "_test", referenced from:
      _main in main.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

编译时报错了,这是最典型的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 
Undefined symbols for architecture x86_64:
  "_test", referenced from:
      _main in main-6ac26d.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

其根本原因也是找不到test()函数的实现文件,由于test()函数的实现在test.a这个静态库中,故在链接的时候需要在其后加入test.a这个库,链接命令修改为如下形式即可。

$ gcc -o main main.c test.a

链接的库文件中又使用了另一个库文件  (这个例子非常非常好, 我就是犯了这种错误!!!)

先更改一下第一个示例中使用到的代码,在test()中调用其它的函数,更改的代码如下所示。


// func.h #ifndef __FUNC_H__ #define __FUNC_H__ void func(); #endif // func.c #include <stdio.h> void func() { printf("call it\n"); } // test.h #ifndef __TEST_H__ #define __TEST_H__ void test(); #endif // test.c #include <string.h> #include <stdio.h> #include "func.h" void test() { printf("just test it\n"); func(); } // main.c #include "test.h" int main(int argc, char **argv) { test(); return 0; }

我们先对fun.c和test.c进行编译,生成.o文件。

$ gcc -c func.c  
$ gcc -c test.c

然后,将test.c和func.c各自打包成为静态库文件。

$ ar –rc func.a func.o  
$ ar –rc test.a test.o 

这时将main.c编译为可执行程序,由于main.c中包含了对test()的调用,因此,应该在链接时将test.a作为我们的库文件,链接命令如下。

$ gcc -o main main.c test.a
Undefined symbols for architecture x86_64:
  "_func", referenced from:
      _test in test.a(test.o)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

就是说,链接的时候发现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 `test':  
test.c:(.text+0x13): undefined reference to `func'  
collect2: ld returned 1 exit status

因此,在链接命令中给出所依赖的库时,需要注意库之间的依赖顺序,依赖其他库的库一定要放到被依赖库的前面,这样才能真正避免undefined reference的错误,完成编译链接。

备注:在MAC上可以正常编译通过。

定义与实现不一致

编写测试代码如下:


// test.h #ifndef __TEST_H__ #define __TEST_H__ void test(unsigned int c); #endif // test.c #include <string.h> #include <stdio.h> void test(int c) { printf("just test it\n"); } // main.c #include "test.h" int main(int argc, char **argv) { test(5); return 0; }

先将test.c编译成库文件。

$ gcc -c test.c 
$ ar -rc test.a test.o

将main.c编译成可执行文件。

$ gcc -o main main.c test.a
ld: warning: ignoring file test.a, file was built for archive which is not the architecture being linked (x86_64): test.a
Undefined symbols for architecture x86_64:
  "_test", referenced from:
      _main in main-f27cf1.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

链接出错了,原因很简单,test()这个函数的声明和定义不一致导致,将两者更改成一样即可通过编译。

在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 with exit 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

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/138447.html原文链接:https://javaforall.net

赞 (0)
全栈程序员-站长的头像全栈程序员-站长

相关推荐

  • L2-021 点赞狂魔(排序)「建议收藏」

    L2-021 点赞狂魔(排序)「建议收藏」原题链接微博上有个“点赞”功能,你可以为你喜欢的博文点个赞表示支持。每篇博文都有一些刻画其特性的标签,而你点赞的博文的类型,也间接刻画了你的特性。然而有这么一种人,他们会通过给自己看到的一切内容点赞来狂刷存在感,这种人就被称为“点赞狂魔”。他们点赞的标签非常分散,无法体现出明显的特性。本题就要求你写个程序,通过统计每个人点赞的不同标签的数量,找出前3名点赞狂魔。输入格式:输入在第一行给出一个正整数N(≤100),是待统计的用户数。随后N行,每行列出一位用户的点赞标签。格式为“Name K F​1​

    2022年8月8日
  • LVS+Keepalived+Nginx+Tomcat高可用负载均衡集群配置「建议收藏」

    LVS+Keepalived+Nginx+Tomcat高可用负载均衡集群配置「建议收藏」一、负载均衡:必不可少的基础手段LVS作用:实现负载均衡Keepalived作用:监控集群系统中各个服务节点的状态,HAcluster。配置LVS有两种方式:1.通过ipvsadm命令行方式配置2.通过Redhat提供的工具piranha来配置LVS1.1找更多的牛来拉车吧  当前大多数的互联网系统都使用了服务器集群技术,集群即将相同服务部署在多台服务器上构成一…

    2022年7月23日
  • excel截取字符串函数_截取函数 excel

    excel截取字符串函数_截取函数 excelExcel中共提供了三种函数来对字符串进行截取操作left(text,num):用于对一个文本字符串,从左向右提取指定个数的字符right(text,num):用于对一个文本字符串,从右向左提取指定个数的字符MID(text,start_num,num_chars):从一个文本字符串的指定位置开始,截取指定个数的字符…

    2022年10月22日
  • C#实现一个局域网文件传输工具

    C#实现一个局域网文件传输工具工作需要,经常会在工作的台式机和笔记本之间传文件或者需要拷贝文本,两个机器都位于局域网内,传文件或者文本的方式有很多种,之前是通过共享文件夹来进行文件的拷贝,或者通过SVN进行同步。文本传递比较简单,可以通过两台机器上装QQ登两个号码,或者在共享目录下建一个TXT,或者发电子邮件等等。不过上面这些方法总觉得不直接,所以想基于P2P做一个小的局域网文件和文字传输小工具。WinForm的工程,

    2022年6月3日
  • webstorm激活【2021最新】

    (webstorm激活)2021最新分享一个能用的的激活码出来,希望能帮到需要激活的朋友。目前这个是能用的,但是用的人多了之后也会失效,会不定时更新的,大家持续关注此网站~IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.net/100143.html…

    2022年3月28日
  • HDU3572_Task Schedule(网络流最大流)[通俗易懂]

    HDU3572_Task Schedule(网络流最大流)

    2022年1月24日

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号