92

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

4 回答 4

129

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

gcc testpoint.c point.c

...以便它知道将两者的功能链接在一起。但是,使用现在编写的代码,您将遇到相反的问题:main. 您将需要/想要消除一个(无疑是 point.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(例如,CFLAGS=-O3打开优化),并且$<是扩展为源文件的名称。

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

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

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

于 2011-04-05T22:20:52.087 回答
25

我最近有这个问题。就我而言,我将 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 致敬,因为他清楚地解释了extern "C" 的效果。)

于 2017-10-26T20:58:50.323 回答
9

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

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

gcc point.c testpoint.c

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

于 2011-04-05T22:22:21.043 回答
4

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

于 2011-04-05T22:25:09.883 回答