【C++】undefined reference to `xxx_function’”的错误

1. undefined reference to `xxx_function’”的错误时

既然编译是说没有定义某个函数,所以我们先看看这个函数是哪一个库实现的。直接搜索编译环境的include目录,看看 xxx_function 这个函数是定义到哪一个头文件,再看看这个函数是哪个源文件实现并编译为库。假设 xxx_function 函数由 xxx.c 实现并最终编译输出为 xxx.so,接着使用readelf -d xxx.so,查看该命令输出的“Library soname:”信息,比如输出了“libxxx.so”,我们再在Makefile的LDFLAGS增加 -lxxx即可,这样编译的时候链接工具将会链接libxxx.so并查找得到xxx_function函数的符号链接成功。
有些时候是没有链接系统的某些库导致的,有时候又会是没有链接第三方库导致的,具体根据问题现象相应查找实现该函数的库,再相应的链接该库即可。

为什么会出现这样的错误呢?
我们在机器中运行一个程序,程序都是由源代码经过预编译、编译、汇编、链接四个阶段组成。

预编译
假设我们的是 .c 源文件和相关头文件,将会被与编译器 gcc 预编译为一个 .i 文件,预编译使用 -E 参数即可。预编译可以简单理解就是处理源码中已“#”开始的预编译指令,比如“#include”、“#define”等。当我们无法判断宏定义是否正确或头文件包含是否正确时,可以查看预编译后的文件来确定问题。

编译
编译过程就是把预处理完的文件进行一系列词法分析、语法分析、语义分析及优化后生成相应的汇编代码文件。使用 - S 参数将输出为汇编文件。

汇编
汇编器就是将汇编代码转换为机器可以执行的指令,每一个汇编语句几乎都对应一条机器指令。使用 -c 参数即可,经过预编译、编译和汇编将会输出目标文件。

链接
我们看汇编代码中,经常会看到 jmp aaa_function,我们知道这个是一个跳转指令,将会跳转到 aaa_function 函数执行,aaa_function 此时是一个符号,我们在编译的时候,最终就会将可执行程序中使用的各个符号链接起来,知道运行的时候到哪里查找得到该符号,知道跳转的地址是多少。链接的过程主要包括了地址和空间分配、符号决议和重定位等这些步骤。

2. undefined reference to `xxx_function’”的错误时

遇到“undefined reference to `xxx_function’”的错误时,通常意味着链接器在链接过程中找不到某个函数的定义。以下是一些解决这类问题的步骤:

  1. 确定函数所属的库

    • 首先,确定xxx_function函数属于哪个库。可以通过搜索头文件来确定函数声明的位置,然后查找该函数是由哪个源文件实现的,以及最终编译成哪个库文件(如libxxx.solibxxx.a)。
  2. 检查库文件是否正确链接

    • 确认在编译命令或Makefile中是否已经包含了正确的库链接指令。如果是动态库,通常使用-lxxx来链接(例如-lyaml-cpp)。如果是静态库,确保.a文件的路径被包含在编译器的搜索路径中,并且使用了-l选项。
  3. 检查库文件的路径

    • 如果库文件不在标准路径下,需要确保编译器能够找到它。可以通过设置-L参数指定库文件的搜索路径。
  4. 检查头文件的路径

    • 确保编译器能够找到库的头文件。可以通过设置-I参数指定头文件的搜索路径。
  5. 检查库的版本

    • 如果库有多个版本,确保链接的是正确的版本。有时候,库的新旧版本之间可能不兼容。
  6. 检查依赖关系

    • 有些库之间存在依赖关系,确保所有依赖库都已经被正确链接。
  7. 使用readelfnm工具

    • 使用readelf -d libxxx.sonm libxxx.so来查看库文件中包含的符号,确认xxx_function是否在其中。
  8. 清理并重新编译

    • 有时候,旧的编译产物可能会导致链接错误。尝试清理(如使用make clean)项目并重新编译。
  9. 检查编译器和链接器的错误信息

    • 仔细阅读编译器和链接器的错误信息,它们通常会提供关于缺失符号的详细信息。
  10. 查看文档和社区

    • 如果上述步骤都无法解决问题,查看库的文档或者搜索社区论坛,看看是否有其他人遇到并解决了类似的问题。

《程序员的自我修养------链接、装载与库》是一本很好的书,它详细介绍了程序从源代码到可执行文件的整个编译链接过程,对于理解链接错误和解决这类问题非常有帮助。

/usr/bin/ld: main.o: in function `main': main.c:(.text.startup+0x16f): undefined reference to `OD_get' /usr/bin/ld: CANopenLinux/CANopenNode/CANopen.o: in function `CO_delete.part.0': CANopen.c:(.text+0x9): undefined reference to `CO_CANmodule_disable' /usr/bin/ld: CANopenLinux/CANopenNode/CANopen.o: in function `CO_CANinit': CANopen.c:(.text+0x351): undefined reference to `CO_CANsetConfigurationMode' /usr/bin/ld: CANopenLinux/CANopenNode/CANopen.o: in function `CO_LSSinit': CANopen.c:(.text+0x3c3): undefined reference to `CO_LSSslave_init' /usr/bin/ld: CANopenLinux/CANopenNode/CANopen.o: in function `CO_CANopenInit': CANopen.c:(.text+0x445): undefined reference to `CO_LEDs_init' /usr/bin/ld: CANopenLinux/CANopenNode/CANopen.o: in function `CO_process': CANopen.c:(.text+0x7c2): undefined reference to `CO_CANmodule_process' /usr/bin/ld: CANopen.c:(.text+0x7cb): undefined reference to `CO_LSSslave_process' /usr/bin/ld: CANopen.c:(.text+0x83b): undefined reference to `CO_LEDs_process' /usr/bin/ld: CANopenLinux/CANopenNode/CANopen.o: in function `CO_process_SYNC': CANopen.c:(.text+0x9c9): undefined reference to `CO_CANclearPendingSyncPDOs' /usr/bin/ld: canopen_common.o: in function `canopen_check_node_reset': canopen_common.c:(.text+0x5dd): undefined reference to `CO_NMT_getResetCommand' /usr/bin/ld: canopen_master.o: in function `canopen_master_send_nmt_command': canopen_master.c:(.text+0xe1): undefined reference to `CO_NMT_sendCommand' /usr/bin/ld: canopen_slave.o: in function `canopen_slave_init': canopen_slave.c:(.text+0x42): undefined reference to `OD_get' /usr/bin/ld: canopen_slave.o: in function `canopen_slave_update_od_data': canopen_slave.c:(.text+0x16b): undefined reference to `OD_getSize' /usr/bin/ld: canopen_slave.c:(.text+0x18e): undefined reference to `OD_stream_init' /usr/bin/ld: canopen_slave.c:(.text+0x1a0): undefined reference to `OD_writeBytes' /usr/bin/ld: canopen_slave.o: in function `canopen_slave_read_od_data': canopen_slave.c:(.text+0x2c7): undefined reference to `OD_getSize' /usr/bin/ld: canopen_slave.c:(.text+0x2e9): undefined reference to `OD_stream_init' /usr/bin/ld: canopen_slave.c:(.text+0x2fb): undefined reference to `OD_readBytes' 编译.o里,有需要链接函数,却显示找不到
最新发布
10-25
### 解决 VSCode 中 `undefined reference to 'xxx'` 编译错误 #### 配置多文件编译环境 当遇到 `undefined reference to 'xxx'` 错误时,通常意味着链接器无法找到某些函数或变量的定义。这可能是由于未正确配置多个源文件之间的依赖关系所致。 对于 C++ 项目而言,确保 `.h` 和 `.cpp` 文件之间的一致性非常重要。具体来说,需确认头文件内的函数签名与实现部分完全匹配[^3]。此外,还需验证是否已将所有必要的源文件加入到构建过程中。 #### 修改 settings.json 设置 Code Runner 执行映射 为了使 VSCode 能够处理多文件项目的编译需求,可以通过调整 `settings.json` 来指定自定义命令用于执行代码。例如: ```json { "code-runner.executorMap": { "cpp": "g++ $fullFileName -o $dir$fileNameWithoutExt && $dir$fileNameWithoutExt" } } ``` 上述 JSON 片段展示了如何通过修改 executor map 让 g++ 同时编译并链接当前工作目录下的所有 cpp 文件[^5]。 #### 添加缺失的 main 函数入口点 有时该类错误也可能源于缺少程序启动所需的主函数(main function),特别是在 Windows 平台上可能会显示为 `undefined reference to WinMain@16` 的形式。此时应检查是否有适当定义了 main 或者其他平台特定的入口函数。 #### 完整示例:创建简单的 C++ 工程结构 下面是一个完整的例子来展示如何组织一个多文件 C++ 应用程序,并确保其可以在 VSCode 下顺利编译运行而不会触发类似的链接失败问题: 假设有一个名为 `fun.h` 的头文件以及对应的实现文件 `fun.cpp`, 还有包含应用程序逻辑起点的 `main.cpp`. - **fun.h** ```c++ #ifndef FUN_H_ #define FUN_H_ void fun(); #endif /*FUN_H_*/ ``` - **fun.cpp** ```c++ #include <iostream> #include "fun.h" void fun() { std::cout << "Function called from another file." << std::endl; } ``` - **main.cpp** ```c++ #include <iostream> #include "fun.h" int main(int argc, char* argv[]) { std::cout << "Hello world!" << std::endl; fun(); return 0; } ``` 最后一步是在终端里输入如下指令来进行手动编译测试(也可以利用之前提到的方法让 code runner 自动完成): ```bash g++ main.cpp fun.cpp -o myapp && ./myapp ``` 这样就可以成功避免出现 `undefined reference` 类型的问题了[^4].
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大江东去浪淘尽千古风流人物

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值