C++ 由于在多个 cpps 中包含相同的标头而导致重复的多个定义错误
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/223771/
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
Repeated Multiple Definition Errors from including same header in multiple cpps
提问by Head Geek
So, no matter what I seem to do, I cannot seem to avoid having Dev C++ spew out numerous Multiple Definition errors as a result of me including the same header file in multiple source code files in the same project. I'd strongly prefer to avoid having to dump all my source code into one file and only include the header once, as that's going to make my file very long and difficult to manage.
因此,无论我似乎做什么,我似乎都无法避免 Dev C++ 由于我在同一项目的多个源代码文件中包含相同的头文件而导致大量多重定义错误。我强烈希望避免将我的所有源代码转储到一个文件中,并且只包含一次标题,因为这会使我的文件变得非常长且难以管理。
Essentially, this is what's going on:
本质上,这就是正在发生的事情:
#ifndef _myheader_h
#define _myheader_h
typedef struct MYSTRUCT{
int blah;
int blah2; } MYSTRUCT;
MYSTRUCT Job_Grunt;
MYSTRUCT *Grunt = &Job_Grunt;
MYSTRUCT Job_Uruk;
MYSTRUCT *Uruk = &Job_Grunt;
int Other_data[100];
void load_jobs();
#endif
Example Cpp File (They pretty much all look something like this):
示例 Cpp 文件(它们几乎都像这样):
#include "myheader.h"
void load_jobs(){
Grunt->blah = 1;
Grunt->blah2 = 14;
Uruk->blah = 2;
Uruk->blah2 = 15;
return; }
Bear in mind that I have about 5 cpp files that include this one header, each one dealing with a different type of struct found in the header file. In this example there was only the one struct containing a couple of members, when there are about 4-6 different structs with many more members in the actual header file. All the files I've included it in follow the same formula as you see in this example here.
请记住,我有大约 5 个包含这个头文件的 cpp 文件,每个文件都处理在头文件中找到的不同类型的结构。在这个例子中,只有一个结构包含几个成员,而实际头文件中大约有 4-6 个不同的结构和更多的成员。我包含在其中的所有文件都遵循与您在此处的示例中看到的相同的公式。
Now I understand that the header guard only stops each individual cpp file from including the header file more than once. What would seem to be happening is that when the compiler reads the include at the start of each cpp, it defines the header file all over again, which is causing it to spit out lines and lines of:
现在我明白头文件保护只会阻止每个单独的 cpp 文件多次包含头文件。似乎正在发生的事情是,当编译器在每个 cpp 的开头读取包含时,它会重新定义头文件,这导致它吐出以下几行:
Multiple Definition of Uruk, first defined here
Multiple Definition of Job_Uruk, first defined here
Multiple Definition of Grunt, first defined here
Multiple Definition of Job_Grunt, first defined here
Multiple Definition of Other_data, first defined here
I'll see a set of this for just about every cpp file in the project which includes the header. I've tried moving the definitions of the struct and the struct variables to the cpp files, but then the other cpp files cannot see them or work with them, which is very important as I need all files in the project to be able to work with these structs.
我将看到项目中几乎每个包含标题的 cpp 文件的一组。我已经尝试将结构和结构变量的定义移动到 cpp 文件,但是其他 cpp 文件无法看到它们或使用它们,这非常重要,因为我需要项目中的所有文件才能工作有了这些结构。
But the single most confusing part about this problem requires a little more explanation:
但是关于这个问题最令人困惑的部分需要更多的解释:
The way I'm setting up these multiple files in this project is identical to the book I'm working with, All In One Game Programming by John S. Harbour. I ran into the exact same problems when I created the files for example projects in the book which called for one header included by multiple cpps in the same project.
我在这个项目中设置这些多个文件的方式与我正在使用的书相同,John S. Harbour 的 All In One Game Programming。当我为书中的示例项目创建文件时,我遇到了完全相同的问题,该文件要求同一项目中的多个 cpp 包含一个标头。
I could type them out, word for word from the book, and I do mean word for word...
and I'd get the series of MD errors for every cpp in the project.
我可以从书中逐字逐句地将它们打出来,而且我的意思是逐字逐句......
而且我会得到项目中每个 cpp 的一系列 MD 错误。
If I loaded the example project from the CD included with the book, it would compile and run without a problem, allthough the files themselves, as well as the project options, were by all appearances identical to the ones I had created.
如果我从本书附带的 CD 中加载示例项目,它会编译和运行没有问题,尽管文件本身以及项目选项在所有外观上都与我创建的相同。
If I created my own project file, and simply added the source and header files for the example project from the CD, this, too, would also compile and run, though I can find no difference between those and mine.
如果我创建了自己的项目文件,并简单地从 CD 中添加示例项目的源文件和头文件,这也将编译和运行,尽管我发现它们和我的没有区别。
So then, I tried making my own project file, then creating the blank source and header files and adding them to it, and then filling them by copying and pasting their contents from the files on the CD they were meant to correspond to(the same ones that had worked). And sure enough, I'd get the same thing...lines and lines of MD error messages.
然后,我尝试制作自己的项目文件,然后创建空白的源文件和头文件并将它们添加到其中,然后通过从它们要对应的 CD 上的文件中复制和粘贴它们的内容来填充它们(相同那些有效的)。果然,我会得到同样的东西......一行又一行的 MD 错误消息。
I'm absolutely baffled. I've repeated all these methods multiple times, and am certain I'm not mistyping or miscopying the code. There just seems to be something about the premade files themselves; some configuration setting or something else I'm missing entirely...that will cause them to compile correctly while the files I make myself won't.
我完全不知所措。我已经多次重复所有这些方法,并且确定我没有错误输入或错误复制代码。似乎有一些关于预制文件本身的东西;一些配置设置或其他我完全遗漏的东西......这将导致它们正确编译,而我自己制作的文件则不会。
回答by Head Geek
Since you're declaring those variables in the header file, and including the header file in each C++ file, each C++ file has its own copy of them.
由于您在头文件中声明了这些变量,并在每个 C++ 文件中包含了头文件,因此每个 C++ 文件都有自己的副本。
The usual way around this is to notdeclare any variables within header files. Instead, declare them in a single C++ file, and declare them as extern
in all the other files that you might need them in.
通常的解决方法是不在头文件中声明任何变量。相反,在单个 C++ 文件中声明它们,并extern
在您可能需要它们的所有其他文件中声明它们。
Another way I've handled this before, which some people might consider unpleasant... declare them in the header file, like this:
我以前处理过的另一种方法,有些人可能会认为不愉快……在头文件中声明它们,如下所示:
#ifdef MAINFILE
#define EXTERN
#else
#define EXTERN extern
#endif
EXTERN MYSTRUCT Job_Grunt;
EXTERN MYSTRUCT *Grunt = &Job_Grunt;
EXTERN MYSTRUCT Job_Uruk;
EXTERN MYSTRUCT *Uruk = &Job_Uruk;
Then, in oneof your C++ files, add a...
然后,在您的一个C++ 文件中,添加一个...
#define MAINFILE
...before your #include
lines. That will take care of everything, and is (in my personal opinion) a lot nicer than having to redeclare all of the variables in every file.
...在你的#include
台词之前。这将处理所有事情,并且(在我个人看来)比必须重新声明每个文件中的所有变量要好得多。
Of course, the realsolution is not to use global variables at all, but when you're just starting out that's hard to achieve.
当然,真正的解决方案根本不是使用全局变量,但是当您刚刚开始时,这很难实现。
回答by Jeremy Ruten
When you define a variable, the compiler sets aside memory for that variable. By defining a variable in the header file, and including that file into all your source files, you are defining the same variable in multiple files.
当您定义一个变量时,编译器会为该变量留出内存。通过在头文件中定义一个变量,并将该文件包含在所有源文件中,您就是在多个文件中定义了相同的变量。
Putting the keyword extern
before a variable definition will tell the compiler that this variable has already been defined somewhere, and that you are only declaring(i.e. naming) the variable so that other files can use it.
将关键字放在extern
变量定义之前将告诉编译器该变量已在某处定义,并且您只是声明(即命名)该变量以便其他文件可以使用它。
So in your header file you should make all your definitions forward declarationsby adding the extern
keyword.
因此,在您的头文件中,您应该通过添加关键字来使所有定义提前声明extern
。
extern MYSTRUCT Job_Grunt;
extern MYSTRUCT *Grunt;
extern MYSTRUCT Job_Uruk;
extern MYSTRUCT *Uruk;
extern int Other_data[100];
And then in one(and only one) of your source files, define the variables normally:
然后在一个(并且只有一个)源文件中,正常定义变量:
MYSTRUCT Job_Grunt;
MYSTRUCT *Grunt = &Job_Grunt;
MYSTRUCT Job_Uruk;
MYSTRUCT *Uruk = &Job_Grunt;
int Other_data[100];
回答by Steve Fallows
While most of the other answers are correct as to why you are seeing multiple definitions, the terminology is imprecise. Understanding declaration vs. definition is the key to your problem.
虽然大多数其他答案对于您为什么会看到多个定义是正确的,但术语是不准确的。理解声明与定义是解决问题的关键。
A declaration announces the existence of an item but does not cause instantiation. Hence the extern statements are declarations - not definitions.
声明会宣布项目的存在,但不会导致实例化。因此 extern 语句是声明 - 而不是定义。
A definition creates an instance of the defined item. Hence if you have a definition in a header it is instantiated in each .cpp file, resulting in the multiple definitions. Definitions are also declarations - i.e. no separate declaration is needed if for instance the scope of the item is limited to one .cpp file.
定义创建已定义项的实例。因此,如果您在标头中有一个定义,它会在每个 .cpp 文件中实例化,从而产生多个定义。定义也是声明——例如,如果项目的范围仅限于一个 .cpp 文件,则不需要单独的声明。
Note: the use of the word instantiation here really only applies to data items.
注意:这里使用的实例化一词实际上仅适用于数据项。
回答by Gerald
You need to define your variables as extern in the header file, and then define them in a cpp file as well. i.e.:
您需要在头文件中将变量定义为 extern,然后也在 cpp 文件中定义它们。IE:
extern MYSTRUCT Job_Grunt;
in your header file, and then in a cpp file in your project declare them normally.
在您的头文件中,然后在您的项目中的 cpp 文件中正常声明它们。
The header file is only for definitions, when you instantiate a variable in the header file it will try to instantiate it every time the header is included in your project. Using the extern directive tells the compiler that it's just a definition and that the instantiation is done somewhere else.
头文件仅用于定义,当您在头文件中实例化一个变量时,它会在每次项目中包含头文件时尝试实例化它。使用 extern 指令告诉编译器它只是一个定义并且实例化是在其他地方完成的。
回答by bpamuk
I also received this error for a function defined in a .h file. The header file was not intended to make declarations of a class but definitions of some functions which are needed in various places in a project. (I may confuse the "definition" and "declaration" usages, but i hope i could give the main idea.) When I put an "inline" keyword just before the definition of the function which give the "multiple definitions" error, the error is avoided.
对于 .h 文件中定义的函数,我也收到了此错误。头文件的目的不是声明一个类,而是定义项目中不同地方需要的一些函数。(我可能会混淆“定义”和“声明”的用法,但我希望我能给出主要思想。)当我在给出“多重定义”错误的函数定义之前放置一个“内联”关键字时,避免了错误。
回答by Nick
To expand on what Gerald said, the header is defining an instance of the struct (which is not what you want). This is causing each compilation unit (cpp file) which includes the header to get its own version of the struct instance, which causes problems at link time.
为了扩展 Gerald 所说的内容,标题定义了结构体的一个实例(这不是您想要的)。这导致包含标头的每个编译单元(cpp 文件)获取其自己的结构实例版本,这会导致链接时出现问题。
As Gerald said, you need to define a reference to the struct (using 'extern') in the header, and have one cpp file in your project which instantiates the instance.
正如 Gerald 所说,您需要在头文件中定义对结构的引用(使用“extern”),并在您的项目中有一个用于实例化实例的 cpp 文件。
回答by Nick
I too was having this problem some time back. Let me try to explain what solved it. I had a global.h file which had all declaration and need to be included in every cpp file. Instead of including it in every .cpp, I included it in .h. All my ".h" files I have added the lines #ifndef and #define and ended with #endif. This solved MD problem. Hope this works for you too.
前段时间我也遇到了这个问题。让我试着解释是什么解决了它。我有一个 global.h 文件,其中包含所有声明并且需要包含在每个 cpp 文件中。我没有将它包含在每个 .cpp 中,而是包含在 .h 中。我所有的“.h”文件都添加了#ifndef 和#define 行,并以#endif 结尾。这解决了MD问题。希望这对你也有用。
回答by jbatista
This is what worked for me: linking the sources into separate libraries. (My problem was not with creating a program but one/many libraries.) I then linked (successfully) one program with the twolibraries I created.
这对我有用:将源链接到单独的库中。(我的问题不在于创建程序,而是创建一个/多个库。)然后我(成功地)将一个程序与我创建的两个库链接在一起。
I had two sets of functions (with one depending on the other) in the same source file, and declared in the same single header file. Then I tried to separate the two function sets in two header+source files.
我在同一个源文件中有两组函数(一组依赖于另一组),并在同一个头文件中声明。然后我尝试在两个头文件+源文件中分离两个函数集。
I tried with both #pragma once and include guards with #ifndef ... #define ... #endif. I also defined the variables and functions as extern in the header files.
我尝试了 #pragma 一次,并使用 #ifndef ... #define ... #endif 包含守卫。我还在头文件中将变量和函数定义为 extern。
As Steve Fallows pointed out, the problem isn't with the compilation but rather with linkage. In my particular problem, I could get away with having two sets of functions, each in its own source file, compiling and then linking into two separate libraries.
正如 Steve Fallows 指出的那样,问题不在于编译,而在于链接。在我的特定问题中,我可以避免使用两组函数,每组函数都在自己的源文件中,编译然后链接到两个单独的库中。
g++ -o grandfather.o -c grandfather.cpp
g++ -o father.o -c father.cpp
g++ -fPIC -shared -o libgf.so grandfather.o
g++ -fPIC -shared -o libfather.so father.o
This forces me to link my programs with both libgf.so and libfather.so. In my particular case it makes no difference; but otherwise I couldn't get them to work together.
这迫使我将我的程序与 libgf.so 和 libfather.so 链接起来。在我的特殊情况下,它没有区别;但否则我无法让他们一起工作。
回答by Brian
GCC 3.4 and up supports #pragma once
. Just put #pragma once
at the top of your code instead of using include guards. This may or may not be more successful, but it's worth a shot. And no, this is not (always) precisely equivalent to an include guard.
GCC 3.4 及更高版本支持#pragma once
. 只需放在#pragma once
代码的顶部,而不是使用包含守卫。这可能会也可能不会更成功,但值得一试。不,这并不(总是)完全等同于包含守卫。