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

时间:2011-04-05 22:18:11

标签: c function linker-errors undefined-reference

只是一个简单的程序,但我不断收到此编译器错误。我正在使用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;
}

我不知道问题是什么。

4 个答案:

答案 0 :(得分:80)

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

gcc testpoint.c point.c

...因此它知道将两者的功能链接在一起。但是,根据现在编写的代码,您将遇到相反的问题:main的多个定义。你需要/想要消除一个(毫无疑问是点c中的那个)。

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

OBJS=testpoint.o point.o

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

第一个只是目标文件名称的宏。您可以使用$(OBJS)进行扩展。第二个规则是告诉make 1)可执行文件依赖于目标文件,2)告诉它如何在/如果它与目标文件相比过时创建可执行文件。

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

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

这假定C编译器的名称位于名为CC的宏中(隐式定义为CC=gcc),并允许您在名为CFLAGS的宏中指定您关心的任何标志(例如,{ {1}}启用优化)CFLAGS=-O3是一个特殊的宏,可以扩展为源文件的名称。

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

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

另请注意1)在涉及大型项目时,如何使用make有很多变化,2)还有很多替代品可供选择。我在这里只打出了最低点。

答案 1 :(得分:7)

我最近遇到过这个问题。在我的例子中,我的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以明确解释effect of extern "C"。)

答案 2 :(得分:6)

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

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

gcc point.c testpoint.c

正如others指出的那样,你还需要删除一个main函数,因为你只能有一个函数。

答案 3 :(得分:2)

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