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

ups*_*sdn 55 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);
Run Code Online (Sandbox Code Playgroud)

这是重点.:

//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;
}
Run Code Online (Sandbox Code Playgroud)

这就是编译器问题的来源.我不断得到:

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;
}
Run Code Online (Sandbox Code Playgroud)

我不知道问题是什么.

Jer*_*fin 84

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

gcc testpoint.c point.c
Run Code Online (Sandbox Code Playgroud)

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

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

OBJS=testpoint.o point.o

testpoint.exe: $(OBJS)
    gcc $(OJBS)
Run Code Online (Sandbox Code Playgroud)

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

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

.c.o:
    $(CC) -c $(CFLAGS) $<
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

  • @TimothySwan:我尝试提供合理的一般性答案,但是,但是有一个限制。将每个答案都输入到教科书中不会对任何人有很大帮助-如果您正在处理一个文件,即使您搜索了该文件,它仍然*相当*一个不同的问题。 (3认同)
  • 这是可行的,但这通常是较大的 C 程序链接/编译在一起的方式吗?头文件中的 extern 关键字似乎没有修复任何问题。 (2认同)

cp.*_*ngr 10

我最近遇到过这个问题.在我的例子中,我的IDE设置为根据其扩展选择在每个文件上使用哪个编译器(C或C++),并且我试图.c从C++代码调用C函数(即从文件中).

.hC函数的文件没有包含在这种防范中:

#ifdef __cplusplus
extern "C" {
#endif

// all of your legacy C code here

#ifdef __cplusplus
}
#endif
Run Code Online (Sandbox Code Playgroud)

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

extern "C" {
#include "legacy_C_header.h"
}
Run Code Online (Sandbox Code Playgroud)

(帽子向UncaAlby提示,因为他清楚地解释了外部"C"的影响.)


Cam*_*Cam 7

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

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

gcc point.c testpoint.c
Run Code Online (Sandbox Code Playgroud)

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