简体   繁体   English

重复多重定义错误,在多个cpps中包含相同的标头

[英]Repeated Multiple Definition Errors from including same header in multiple cpps

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. 因此,无论我做什么,我似乎都无法避免由于我在同一项目中的多个源代码文件中包含相同的头文件而使Dev C ++发出大量多重定义错误。 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. 我非常希望避免将我的所有源代码转储到一个文件中,并且只包含一次标题,因为这将使我的文件很长并且难以管理。

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. 请记住,我有大约5个包含这个标题的cpp文件,每个文件都处理头文件中找到的不同类型的结构。 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. 在这个例子中,当实际头文件中有大约4-6个不同的结构,并且有更多的成员时,只有一个结构包含几个成员。 All the files I've included it in follow the same formula as you see in this example here. 我在其中包含的所有文件都遵循您在此示例中看到的相同公式。

Now I understand that the header guard only stops each individual cpp file from including the header file more than once. 现在我明白了标头防护只能阻止每个单独的cpp文件多次包含头文件。 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的开头读取include时,它会再次定义头文件,这会导致它吐出以下行和行:

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. 我会在项目中看到一组包含标题的cpp文件。 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. 我已经尝试将struct和struct变量的定义移动到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. 我在这个项目中设置这些多个文件的方式与我正在使用的书,John S. Harbour的All In One Game Programming相同。 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. 当我在书中创建示例项目的文件时,我遇到了完全相同的问题,该项目要求在同一项目中包含多个cpps的一个头文件。

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). 那么,我尝试制作我自己的项目文件,然后创建空白的源文件和头文件并将其添加到文件中,然后通过复制并粘贴它们要与之对应的CD上的文件来填充它们(相同)那些曾经工作的人)。 And sure enough, I'd get the same thing...lines and lines of MD error messages. 当然,我会得到同样的东西...... 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. 一些配置设置或其他我完全错过的东西...这将导致他们正确编译,而我自己制作的文件不会。

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 not declare 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 one of your C++ files, add a... 然后,在您的一个 C ++文件中,添加一个...

#define MAINFILE

...before your #include lines. ...在#include行之前。 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. 这将照顾一切,并且(在我个人看来)比在每个文件中重新声明所有变量要好得多。

Of course, the real solution is not to use global variables at all, but when you're just starting out that's hard to achieve. 当然, 真正的解决方案根本不是使用全局变量,而是当你刚刚开始时很难实现。

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 (ie naming) the variable so that other files can use it. 将关键字extern放在变量定义之前将告诉编译器该变量已经在某处定义,并且您只是声明 (即命名)变量以便其他文件可以使用它。

So in your header file you should make all your definitions forward declarations by 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];

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. 因此,外部声明是声明 - 而不是定义。

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. 因此,如果您在标头中有定义,则会在每个.cpp文件中实例化,从而产生多个定义。 Definitions are also declarations - ie no separate declaration is needed if for instance the scope of the item is limited to one .cpp file. 定义也是声明 - 即,例如,如果项目的范围限于一个.cpp文件,则不需要单独的声明。

Note: the use of the word instantiation here really only applies to data items. 注意:这里使用单词instantiation实际上只适用于数据项。

You need to define your variables as extern in the header file, and then define them in a cpp file as well. 您需要在头文件中将变量定义为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指令告诉编译器它只是一个定义,并且实例化在其他地方完成。

I also received this error for a function defined in a .h file. 我还收到了.h文件中定义的函数的此错误。 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. (我可能会混淆“定义”和“声明”用法,但我希望我能提出主要想法。)当我在函数定义之前放置一个“内联”关键字时会产生“多个定义”错误,错误是避免的。

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 two libraries 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. 我曾尝试使用#pragma和#ifndef ... #define ... #endif。 I also defined the variables and functions as extern in the header files. 我还在头文件中将变量和函数定义为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 . 在我的特定问题中,我可以使用两组函数,每个函数都在自己的源文件中,编译然后链接到两个独立的库中

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. 这迫使我将我的程序与libgf.so和libfather.so联系起来。 In my particular case it makes no difference; 在我的特殊情况下,它没有任何区别; but otherwise I couldn't get them to work together. 但除此之外我无法让他们一起工作。

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. 这导致包含头的每个编译单元(cpp文件)获得其自己的struct实例版本,这会在链接时引起问题。

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所说,你需要在头文件中定义对struct的引用(使用'extern'),并在项目中有一个cpp文件来实例化实例。

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. 我有一个global.h文件,它有所有声明,需要包含在每个cpp文件中。 Instead of including it in every .cpp, I included it in .h. 我把它包含在.h中,而不是将它包含在每个.cpp中。 All my ".h" files I have added the lines #ifndef and #define and ended with #endif. 我的所有“.h”文件都添加了#ifndef和#define行,并以#endif结束。 This solved MD problem. 这解决了MD问题。 Hope this works for you too. 希望这也适合你。

GCC 3.4 and up supports #pragma once . GCC 3.4及更高版本支持#pragma once Just put #pragma once at the top of your code instead of using include guards. 只需将#pragma once放在代码顶部,而不是使用包含保护。 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. 不,这不是(总是)精确等同于包含守卫。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM