【问题标题】:Undefined symbols error when using a header file使用头文件时出现未定义符号错误
【发布时间】:2011-02-27 15:54:57
【问题描述】:

我遇到了以下错误,我一生都无法弄清楚我做错了什么。

$ gcc main.c -o main

Undefined symbols:
  "_wtf", referenced from:
      _main in ccu2Qr2V.o
ld: symbol(s) not found
collect2: ld returned 1 exit status

ma​​in.c:

#include <stdio.h>
#include "wtf.h"

main(){
    wtf();
}

wtf.h:

void wtf();

wtf.c:

void wtf(){
    printf("I never see the light of day.");
}

现在,如果我在头文件中包含整个函数而不仅仅是签名,它会很好地符合要求,所以我知道 wtf.h 被包含在内。为什么编译器看不到 wtf.c?还是我错过了什么?

问候。

【问题讨论】:

  • 你从来没有告诉编译器编译 wtf.c。这就是为什么。
  • 是的,我来自魔法和独角兽之地,所以我只是假设将实现命名为与标头相同的名称将允许编译器找到两者。

标签: c linker-errors undefined-reference undefined-symbol


【解决方案1】:

您错过了这样一个事实,即仅包含标头并不会告诉编译器有关标头中声明的事物的实际实现(定义)在哪里。

它们可能位于执行包含的文件旁边的 C 文件中,它们可能来自预编译的静态链接库,或在读取可执行文件时由系统链接器加载的动态库,或者它们可能在运行时出现-time 用户程序员控制的显式动态加载(例如,Linux 中的@987654321@ 系列函数)。

C 不像 Java,没有隐含的规则就是因为 C 文件包含某个头文件,编译器也应该做一些事情来“神奇地”找到头文件中声明的东西的实现。你需要告诉它。

【讨论】:

  • 你完全正确。我假设只要头文件和实现的名称相同,编译器就会在我包含头文件时找到它们。
  • 这个为什么单独编译是一个特性的解释非常有用。谢谢。
【解决方案2】:

您需要将wtf 与您的main 关联。将它编译在一起的最简单方法 - gcc 将为您链接它们,如下所示:

gcc main.c wtf.c -o main

更长的路(wtf的单独编译):

gcc -c wtf.c
gcc main.c wtf.o -o main

甚至更长(单独编译和链接)

gcc -c wtf.c
gcc -c main.c
gcc main.o wtf.o -o main

您可以直接运行ld 而不是最后一次gcc 调用,效果相同。

【讨论】:

  • 那么是什么阻止我做以下事情? #include #include "wtf.h" #include "wtf.c" 感觉很不愉快,但是当我运行 gcc 时必须为每个实现都包含一个参数的想法也是如此。
  • @j33r:大概没有什么能阻止我们,我们需要通过编写 C++ 代码来赚钱谋生,然而,我们的同事阻止我们这样做,以保护他们的理智。 (如果你真的不知道:C 的关键特性之一是单独编译。除此之外,它允许我们处理包含预处理器文件的疯狂编译时间。并且然后还有信息隐藏、封装和其他很好的——不幸的是,经常被低估的——原则。)
  • @j33r:当您的程序有多个.c 文件时,是时候编写一个简单的Makefile 来构建它了。
猜你喜欢
  • 2022-11-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-16
  • 2015-01-16
  • 2014-04-15
  • 2020-06-06
  • 1970-01-01
相关资源
最近更新 更多