C语言 C 错误:未定义对函数的引用,但已定义
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5559250/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
C error: undefined reference to function, but it IS defined
提问by upswimsdn
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:
这是头文件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);
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)'
testpoint.c:未定义对“create(double x,double 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.
我不知道问题可能是什么。
回答by Jerry Coffin
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. 您将需要/想要消除一个(无疑是 point.c 中的那个)。
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 maketo 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 it 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:
大多数版本的 make(包括 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=-O3to turn on optimization) and $<is a special macro that expands to the name of the source file.
这是假设C编译器的名称是在宏命名为CC(如隐含定义CC=gcc),并允许您指定关心名为宏任何标志CFLAGS(例如,CFLAGS=-O3打开优化),并$<是一个特殊的宏展开成源文件的名称。
You typically store this in a file named Makefile, and to build your program, you just type makeat 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 makeautomatically 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).
这样做的好处是它会make自动查看文件上的时间戳,因此它只会重新编译自上次编译后发生更改的文件(即“.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.
另请注意,1) 在大型项目中如何使用 make 有很多变化,2) 还有很多替代方法。我在这里只触及了最低限度的高点。
回答by cp.engr
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 .cfile) from C++ code.
我最近有这个问题。就我而言,我将 IDE 设置为根据每个文件的扩展名选择在每个文件上使用哪个编译器(C 或 C++),并且我试图.c从 C++ 代码调用 C 函数(即从文件中)。
The .hfile for the C function wasn't wrapped in this sort of guard:
.hC 函数的文件没有包含在这种保护中:
#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 UncaAlbyfor his clear explanation of the effect of extern "C".)
(感谢 UncaAlby对extern "C" 效果的清晰解释。)
回答by Cam
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 时,它包含 point.h 但它不知道 point.c。由于 point.c 有 的定义create,没有 point.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
As othershave pointed out, you also need to remove one of your mainfunctions, since you can only have one.
正如其他人指出的那样,您还需要删除一个main功能,因为您只能拥有一个。
回答by Richard Schneider
Add the "extern" keyword to the function definitions in point.h
将“extern”关键字添加到 point.h 中的函数定义

