C 错误:未定义对函数的引用,但已定义

C error: undefined reference to function, but it IS defined

提问人:upswimsdn 提问时间:4/6/2011 最后编辑:alkupswimsdn 更新时间:2/15/2023 访问量:575293

问:

只是一个简单的程序,但我不断收到这个编译器错误。我正在使用MinGW作为编译器。

下面是头文件 point.h

//type for a Cartesian point
typedef struct {
  double x;
  double y;
} Point;

Point create(double x, double y);
Point midpoint(Point p, Point q);

这是 point.c

//This is the implementation of the point type
#include "point.h"

int main() {
  return 0;
}
Point create(double x, double y) {
  Point p;
  p.x = x;
  p.y = y;
  return p;
}

Point midpoint(Point p, Point q) {
  Point mid;
  mid.x = (p.x + q.x) / 2;
  mid.y = (p.y + q.y) / 2;
  return mid;
}

这就是编译器问题所在。我一直得到:

testpoint.c:对“create(double x, double y)”的未定义引用

虽然它在 point.c 中定义。

这是一个名为 testpoint.c 的单独文件:

#include "point.h"
#include <assert.h>
#include <stdio.h>
int main() {
  double x = 1;
  double y = 1;
  Point p = create(x, y);

  assert(p.x == 1);
  return 0;
}

我对问题可能是什么感到茫然。

c 函数 链接器错误 未定义引用

评论

9赞 George 4/6/2011
你能发布你的makefile吗?此外,您定义了 2 个主要功能,这不可能是好的。
0赞 RageD 4/6/2011
可能重新定义哪个是程序的入口点。摆脱main()point.c
0赞 Chan Kim 3/10/2016
@upswimsdn,是因为main()的双重定义吗?
2赞 upswimsdn 3/11/2016
是的,这是我遇到的另一个问题,但主要问题是没有使用“gcc testpoint.c point.c”将两个文件编译在一起(请参阅公认的答案)。

答:

149赞 Jerry Coffin 4/6/2011 #1

你是如何进行编译和链接的?您需要指定这两个文件,如下所示:

gcc testpoint.c point.c

...这样它就知道将两者的函数链接在一起。但是,使用现在编写的代码时,您将遇到相反的问题:.您将需要/想要消除一个(无疑是 point.c 中的那个)。main

在较大的程序中,通常单独编译和链接,以避免重新编译任何未更改的内容。您通常通过 makefile 指定需要完成的工作,并用于执行工作。在这种情况下,你会有这样的结果:make

OBJS=testpoint.o point.o

testpoint.exe: $(OBJS)
    gcc $(OJBS)

第一个只是对象文件名称的宏。你可以用 .第二个规则是告诉 make 1) 可执行文件依赖于目标文件,以及 2) 告诉它如何创建可执行文件,当它与目标文件相比已经过时时。$(OBJS)

大多数版本的 make(包括 MinGW 中的版本,我很确定)都有一个内置的“隐式规则”来告诉他们如何从 C 源文件创建对象文件。它通常大致如下所示:

.c.o:
    $(CC) -c $(CFLAGS) $<

这假定 C 编译器的名称位于名为 CC 的宏中(隐式定义为 ),并允许您在名为 的宏中指定您关心的任何标志(例如,打开优化),并且是一个扩展为源文件名称的特殊宏。CC=gccCFLAGSCFLAGS=-O3$<

通常将其存储在名为 的文件中,要构建程序,只需在命令行中键入即可。它隐式查找名为 的文件,并运行它包含的任何规则。MakefilemakeMakefile

这样做的好处是,它会自动查看文件上的时间戳,因此它只会重新编译自上次编译以来已更改的文件(即,“.c”文件的时间戳比匹配的“.o”文件更新)。make

另请注意,1) 在大型项目中,如何使用 make 有很多变化,以及 2) 也有很多替代方案可供制作。我在这里只触及了最低限度的高点。

评论

2赞 upswimsdn 4/6/2011
这是可行的,但这通常是将较大的 C 程序链接/编译在一起的方式吗?头文件中的 extern 关键字似乎没有解决任何问题。
1赞 Timothy Swan 2/21/2018
似乎你的回答只够解决提问者的问题。这与回答问题不同。例如,我有与标题中完全相同的问题,但所有内容都在一个文件中。stackoverflow 的目的是提供可搜索的答案,而不仅仅是帮助某人一次,然后误导任何搜索同一问题的人。
4赞 Jerry Coffin 2/21/2018
@TimothySwan:我试图提供合理的一般答案,这是有限制的。把每个答案都写进教科书对任何人都没有多大帮助——如果你正在处理一个文件,即使你的搜索结果显示了这一点,它仍然是一个完全不同的问题。
0赞 Zirui Bai 2/27/2020
@JerryCoffin 感谢您的回答!然而,这给了我另一个问题:当我们使用一些库函数(如 printf)时,我们通常不会在编译过程中将库文件添加到 gcc 命令中。我们只需要包含 stdio.h 就可以了。我描述的情况和问题中的情况有什么区别吗?
1赞 Jerry Coffin 2/27/2020
@ZiruiBai:唯一真正的区别是,当(或大多数其他编译器)生成链接器时,默认情况下它会告诉链接器链接到标准库。但是,对于任何其他库来说,这不会发生(对于标准库中的任何数学函数来说,这通常都不会发生——至少在大多数情况下,你需要显式链接它)。gcc
10赞 Cam 4/6/2011 #2

我认为问题在于,当您尝试编译testpoint.c时,它包含point.h,但它不知道point.c。由于 point.c 具有 的定义,因此没有 point.c 将导致编译失败。create

我不熟悉 MinGW,但你需要告诉编译器寻找 point.c。例如,使用 gcc,您可以这样做:

gcc point.c testpoint.c

正如其他人指出的那样,您还需要删除其中一个功能,因为您只能拥有一个。main

4赞 Richard Schneider 4/6/2011 #3

将“extern”关键字添加到 point.h 中的函数定义中

评论

8赞 Engineer 11/5/2014
extern对函数没有任何影响(至少现在是这样),因为在标头中声明的每个函数都是公共/外部的。
1赞 endolith 8/12/2021
从函数定义中删除“static”关键字
34赞 cp.engr 10/27/2017 #4

我最近遇到了这个问题。就我而言,我将 IDE 设置为根据每个文件的扩展名选择要在每个文件上使用的编译器(C 或 C++),并且我尝试从 C++ 代码调用 C 函数(即从文件调用)。.c

C 函数的文件没有包装在这种保护中:.h

#ifdef __cplusplus
extern "C" {
#endif

// all of your legacy C code here

#ifdef __cplusplus
}
#endif

我本可以添加它,但我不想修改它,所以我只是把它包含在我的 C++ 文件中,如下所示:

extern "C" {
#include "legacy_C_header.h"
}

(感谢 UncaAlby外部“C”效果的明确解释。

0赞 Neuwelt 5/3/2022 #5

我遇到了类似的问题,在一个目录中运行一堆 .c 文件,所有文件都链接到一个带有自定义函数原型的头文件。 我跑了:

$gcc -Wall -Werror -Wextra -pedantic -std=gnu89 *.c

出现以下错误:

/usr/bin/ld: /tmp/ccovH4zH.o: in function `_puts': 3-puts.c:(.text+0x2f): undefined reference to `_putchar'
/usr/bin/ld: 3-puts.c:(.text+0x51): undefined reference to `_putchar'
/usr/bin/ld: /tmp/ccGeWRqI.o: in function `main': _putchar.c:(.text+0xe): undefined reference to `_putchar'
/usr/bin/ld: _putchar.c:(.text+0x18): undefined reference to `_putchar'
/usr/bin/ld: _putchar.c:(.text+0x22): undefined reference to `_putchar'
/usr/bin/ld: /tmp/ccGeWRqI.o:_putchar.c:(.text+0x2c): more undefined references to `_putchar' follow
collect2: error: ld returned 1 exit status

注意:所有文件都链接到具有所有函数声明的同一头文件。

在向 gcc 编译器添加 -c 选项后,我设法成功编译,例如:

$gcc -Wall -Werror -Wextra -pedantic -std=gnu89 -c *.c

此操作成功运行。

以防万一有人遇到同样的情况。

评论

0赞 Celuk 11/18/2022
但是,这并不能解决问题。使用选项,它只是将 c 代码编译为目标代码,因为它们是依赖的,它们不能单独执行,要创建可执行文件,您需要链接它们,它可能会再次给出相同的错误。-c