C错误:未定义的函数引用,但它被定义
只是一个简单的程序,但我不断收到这个编译器错误。 我正在使用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; px = x; py = y; return p; } Point midpoint(Point p, Point q) { Point mid; mid.x = (px + qx) / 2; mid.y = (py + qy) / 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(px == 1); return 0; }
我对这个问题可能会感到不知所措。
你怎么做编译和链接? 你需要指定两个文件,如下所示:
gcc testpoint.c point.c
…所以它知道把两者的function连接在一起。 然而,如果现在编写代码,则会遇到相反的问题: main
多个定义。 你需要/想要消除一个(无疑是point.c中的一个)。
编辑:在一个更大的程序中,你通常分别编译和链接,以避免重新编译任何没有改变的东西。 您通常通过makefile指定需要完成的工作,并使用make
来完成工作。 在这种情况下,你会有这样的事情:
OBJS=testpoint.o point.o testpoint.exe: $(OBJS) gcc $(OJBS)
第一个是对象文件名称的macros。 你得到$(OBJS)
扩展。 第二个是告诉make 1)可执行文件依赖于目标文件的规则,2)告诉它如何在/如果与目标文件相比已经过期时如何创build可执行文件。
make的大多数版本(包括MinGW中的一个我都很确定)都有一个内置的“隐式规则”来告诉他们如何从C源文件创build一个目标文件。 它通常看起来大致是这样的:
.co: $(CC) -c $(CFLAGS) $<
这假设C编译器的名称是一个名为CC的macros(隐式定义,如CC=gcc
),并允许您在名为CFLAGS
的macros中指定您关心的任何标志(例如, CFLAGS=-O3
打开优化), $<
是一个扩展到源文件名称的特殊macros。
您通常将其存储在一个名为Makefile
,然后构build您的程序,只需在命令行键入make
。 它隐式地查找一个名为Makefile
,并运行它包含的任何规则。
这样做的好处是make
自动查看文件上的时间戳,所以它只会重新编译自上次编译以来发生更改的文件(即“.c”文件更多的文件最近的时间戳比匹配的“.o”文件)。
还要注意:1)在大型项目中,如何使用make有很多变化,2)也有很多替代品。 我只打这里的最高点。
我认为问题是,当你正在编译testpoint.c时,它包含了point.h,但它并不知道point.c。 由于point.c具有create
的定义,没有point.c会导致编译失败。
我不熟悉MinGW,但你需要告诉编译器寻找point.c。 例如使用gcc你可能会这样做:
gcc point.c testpoint.c
当然,正如其他人指出的,你也需要删除你的main
function之一,因为你只能有一个。
将“extern”关键字添加到point.h中的函数定义中
我最近有这个问题。 在我的情况下,我让我的IDE根据其扩展名来select在每个文件上使用哪个编译器(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”的效果,所以给UncaAlby一个小贴士 。)