C错误:未定义的函数引用,但定义了。

时间:2022-11-06 09:40:07

Just a simple program, but I keep getting this compiler error. I'm using MinGW for the compiler.

只是一个简单的程序,但我一直得到这个编译器错误。我正在使用MinGW作为编译器。

Here's the header file, point.h:

这是头文件,点。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);

And here's point.c:

这里是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;
}

And here's where the compiler issue comes in. I keep getting:

这就是编译器的问题所在。我继续:

testpoint.c: undefined reference to 'create(double x, double y)'

测试点。c:未定义的“创建(双x,双y)”

While it is defined in point.c.

虽然它是在point.c中定义的。

This is a separate file called testpoint.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;
}

I'm at a loss as to what the issue could be.

我对这个问题可能会是什么感到茫然。

4 个解决方案

#1


63  

How are you doing the compiling and linking? You'll need to specify both files, something like:

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

gcc testpoint.c point.c

...so that it knows to link the functions from both together. With the code as it's written right now, however, you'll then run into the opposite problem: multiple definitions of main. You'll need/want to eliminate one (undoubtedly the one in point.c).

…这样它就知道把两个函数联系起来。但是,随着代码的编写,您将遇到相反的问题:main的多个定义。你需要/想要消除一个(毫无疑问是一个点)。

Edit: In a larger program, you typically compile and link separately to avoid re-compiling anything that hasn't changed. You normally specify what needs to be done via a makefile, and use make to do the work. In this case you'd have something like this:

编辑:在一个较大的程序中,您通常会分别编译和链接,以避免重新编译没有更改的内容。您通常会指定需要通过makefile完成的工作,并使用make来完成工作。在这种情况下,你会得到这样的东西:

OBJS=testpoint.o point.o

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

The first is just a macro for the names of the object files. You get is expanded with $(OBJS). The second is a rule to tell make 1) that the executable depends on the object files, and 2) telling it how to create the executable when/if it's out of date compared to an object file.

第一个是对象文件名称的宏。您得到的是$(OBJS)。第二个是规则,告诉make 1)可执行文件依赖于对象文件,2)告诉它如何创建可执行文件,当/如果它与对象文件比较过时。

Most versions of make (including the one in MinGW I'm pretty sure) have a built-in "implicit rule" to tell them how to create an object file from a C source file. It normally looks roughly like this:

大多数版本(包括在MinGW中使用的版本)都有一个内置的“隐式规则”,告诉他们如何从C源文件创建对象文件。它通常是这样的:

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

This assumes the name of the C compiler is in a macro named CC (implicitly defined like CC=gcc) and allows you to specify any flags you care about in a macro named CFLAGS (e.g., CFLAGS=-O3 to turn on optimization) and $< is a special macro that expands to the name of the source file.

这个假设C编译器在一个宏的名字叫CC(隐式定义像CC = gcc),允许您指定任何旗帜你关心宏观命名CFLAGS(例如,CFLAGS = o3打开优化)和 <美元是一个特定的宏,它扩大到源文件的名称。< p>

You typically store this in a file named Makefile, and to build your program, you just type make at the command line. It implicitly looks for a file named Makefile, and runs whatever rules it contains.

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

The good point of this is that make automatically looks at the timestamps on the files, so it will only re-compile the files that have changed since the last time you compiled them (i.e., files where the ".c" file has a more recent time-stamp than the matching ".o" file).

这样做的好处是,可以自动地查看文件上的时间戳,因此它只会重新编译自上次编译后发生更改的文件(即:,文件在这里。c“文件的时间戳比匹配的时间更近”。o”文件)。

Also note that 1) there are lots of variations in how to use make when it comes to large projects, and 2) there are also lots of alternatives to make. I've only hit on the bare minimum of high points here.

同样要注意的是,当涉及到大型项目时,在如何使用make方面有很多不同之处,而且还有很多其他的选择。我在这里只触及了最低限度。

#2


6  

I think the problem is that when you're trying to compile testpoint.c, it includes point.h but it doesn't know about point.c. Since point.c has the definition for create, not having point.c will cause the compilation to fail.

我认为问题在于,当您试图编译testpoint时。c,它包括点。但是它不知道点。因为点。c有创建的定义,没有点。c将导致编译失败。

I'm not familiar with MinGW, but you need to tell the compiler to look for point.c. For example with gcc you might do this:

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

gcc point.c testpoint.c

Of course as others have pointed out, you also need to remove one of your main functions, since you can only have one.

当然,正如其他人指出的那样,你也需要删除你的一个主要功能,因为你只能有一个。

#3


4  

I had this issue recently. In my case, I had my IDE set to choose which compiler (C or C++) to use on each file according to its extension, and I was trying to call a C function (i.e. from a .c file) from C++ code.

我最近有这个问题。在我的例子中,我有一个IDE集来选择哪个编译器(C或c++)根据它的扩展来使用每个文件,并且我尝试从c++代码调用一个C函数(即从. C文件)。

The .h file for the C function wasn't wrapped in this sort of guard:

C函数的。h文件没有被这样的保护包括起来:

#ifdef __cplusplus
extern "C" {
#endif

// all of your legacy C code here

#ifdef __cplusplus
}
#endif

I could've added that, but I didn't want to modify it, so I just included it in my C++ file like so:

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

extern "C" {
#include "legacy_C_header.h"
}

(Hat tip to UncaAlby for his clear explanation of the effect of extern "C".)

(向UncaAlby致敬,他清楚地解释了外部“C”的影响。)

#4


3  

Add the "extern" keyword to the function definitions in point.h

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

#1


63  

How are you doing the compiling and linking? You'll need to specify both files, something like:

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

gcc testpoint.c point.c

...so that it knows to link the functions from both together. With the code as it's written right now, however, you'll then run into the opposite problem: multiple definitions of main. You'll need/want to eliminate one (undoubtedly the one in point.c).

…这样它就知道把两个函数联系起来。但是,随着代码的编写,您将遇到相反的问题:main的多个定义。你需要/想要消除一个(毫无疑问是一个点)。

Edit: In a larger program, you typically compile and link separately to avoid re-compiling anything that hasn't changed. You normally specify what needs to be done via a makefile, and use make to do the work. In this case you'd have something like this:

编辑:在一个较大的程序中,您通常会分别编译和链接,以避免重新编译没有更改的内容。您通常会指定需要通过makefile完成的工作,并使用make来完成工作。在这种情况下,你会得到这样的东西:

OBJS=testpoint.o point.o

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

The first is just a macro for the names of the object files. You get is expanded with $(OBJS). The second is a rule to tell make 1) that the executable depends on the object files, and 2) telling it how to create the executable when/if it's out of date compared to an object file.

第一个是对象文件名称的宏。您得到的是$(OBJS)。第二个是规则,告诉make 1)可执行文件依赖于对象文件,2)告诉它如何创建可执行文件,当/如果它与对象文件比较过时。

Most versions of make (including the one in MinGW I'm pretty sure) have a built-in "implicit rule" to tell them how to create an object file from a C source file. It normally looks roughly like this:

大多数版本(包括在MinGW中使用的版本)都有一个内置的“隐式规则”,告诉他们如何从C源文件创建对象文件。它通常是这样的:

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

This assumes the name of the C compiler is in a macro named CC (implicitly defined like CC=gcc) and allows you to specify any flags you care about in a macro named CFLAGS (e.g., CFLAGS=-O3 to turn on optimization) and $< is a special macro that expands to the name of the source file.

这个假设C编译器在一个宏的名字叫CC(隐式定义像CC = gcc),允许您指定任何旗帜你关心宏观命名CFLAGS(例如,CFLAGS = o3打开优化)和 <美元是一个特定的宏,它扩大到源文件的名称。< p>

You typically store this in a file named Makefile, and to build your program, you just type make at the command line. It implicitly looks for a file named Makefile, and runs whatever rules it contains.

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

The good point of this is that make automatically looks at the timestamps on the files, so it will only re-compile the files that have changed since the last time you compiled them (i.e., files where the ".c" file has a more recent time-stamp than the matching ".o" file).

这样做的好处是,可以自动地查看文件上的时间戳,因此它只会重新编译自上次编译后发生更改的文件(即:,文件在这里。c“文件的时间戳比匹配的时间更近”。o”文件)。

Also note that 1) there are lots of variations in how to use make when it comes to large projects, and 2) there are also lots of alternatives to make. I've only hit on the bare minimum of high points here.

同样要注意的是,当涉及到大型项目时,在如何使用make方面有很多不同之处,而且还有很多其他的选择。我在这里只触及了最低限度。

#2


6  

I think the problem is that when you're trying to compile testpoint.c, it includes point.h but it doesn't know about point.c. Since point.c has the definition for create, not having point.c will cause the compilation to fail.

我认为问题在于,当您试图编译testpoint时。c,它包括点。但是它不知道点。因为点。c有创建的定义,没有点。c将导致编译失败。

I'm not familiar with MinGW, but you need to tell the compiler to look for point.c. For example with gcc you might do this:

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

gcc point.c testpoint.c

Of course as others have pointed out, you also need to remove one of your main functions, since you can only have one.

当然,正如其他人指出的那样,你也需要删除你的一个主要功能,因为你只能有一个。

#3


4  

I had this issue recently. In my case, I had my IDE set to choose which compiler (C or C++) to use on each file according to its extension, and I was trying to call a C function (i.e. from a .c file) from C++ code.

我最近有这个问题。在我的例子中,我有一个IDE集来选择哪个编译器(C或c++)根据它的扩展来使用每个文件,并且我尝试从c++代码调用一个C函数(即从. C文件)。

The .h file for the C function wasn't wrapped in this sort of guard:

C函数的。h文件没有被这样的保护包括起来:

#ifdef __cplusplus
extern "C" {
#endif

// all of your legacy C code here

#ifdef __cplusplus
}
#endif

I could've added that, but I didn't want to modify it, so I just included it in my C++ file like so:

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

extern "C" {
#include "legacy_C_header.h"
}

(Hat tip to UncaAlby for his clear explanation of the effect of extern "C".)

(向UncaAlby致敬,他清楚地解释了外部“C”的影响。)

#4


3  

Add the "extern" keyword to the function definitions in point.h

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