提问人:upswimsdn 提问时间:4/6/2011 最后编辑:alkupswimsdn 更新时间:2/15/2023 访问量:575293
C 错误:未定义对函数的引用,但已定义
C error: undefined reference to function, but it IS defined
问:
只是一个简单的程序,但我不断收到这个编译器错误。我正在使用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;
}
我对问题可能是什么感到茫然。
答:
你是如何进行编译和链接的?您需要指定这两个文件,如下所示:
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=gcc
CFLAGS
CFLAGS=-O3
$<
通常将其存储在名为 的文件中,要构建程序,只需在命令行中键入即可。它隐式查找名为 的文件,并运行它包含的任何规则。Makefile
make
Makefile
这样做的好处是,它会自动查看文件上的时间戳,因此它只会重新编译自上次编译以来已更改的文件(即,“.c”文件的时间戳比匹配的“.o”文件更新)。make
另请注意,1) 在大型项目中,如何使用 make 有很多变化,以及 2) 也有很多替代方案可供制作。我在这里只触及了最低限度的高点。
评论
gcc
我认为问题在于,当您尝试编译testpoint.c时,它包含point.h,但它不知道point.c。由于 point.c 具有 的定义,因此没有 point.c 将导致编译失败。create
我不熟悉 MinGW,但你需要告诉编译器寻找 point.c。例如,使用 gcc,您可以这样做:
gcc point.c testpoint.c
正如其他人指出的那样,您还需要删除其中一个功能,因为您只能拥有一个。main
将“extern”关键字添加到 point.h 中的函数定义中
评论
extern
对函数没有任何影响(至少现在是这样),因为在标头中声明的每个函数都是公共/外部的。
我最近遇到了这个问题。就我而言,我将 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"
}
我遇到了类似的问题,在一个目录中运行一堆 .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
此操作成功运行。
以防万一有人遇到同样的情况。
评论
-c
评论
main()
point.c