Repeated Multiple Definition Errors from including same header in multiple cpps
Asked Answered
C

9

15

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.

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):

#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.

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:

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.

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.

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.

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.

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.

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.

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.

Comparable answered 21/10, 2008 at 22:27 Comment(0)
P
26

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.

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.

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...

#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.

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.

Pyatt answered 21/10, 2008 at 22:36 Comment(0)
B
13

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.

So in your header file you should make all your definitions forward declarations by adding the extern keyword.

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];
Brownson answered 21/10, 2008 at 22:41 Comment(0)
B
6

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. 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.

Note: the use of the word instantiation here really only applies to data items.

Bysshe answered 22/10, 2008 at 1:21 Comment(0)
S
5

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 MYSTRUCT Job_Grunt;

in your header file, and then in a cpp file in your project declare them normally.

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.

Sexagenary answered 21/10, 2008 at 22:32 Comment(0)
G
2

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.

Graupel answered 7/6, 2011 at 9:9 Comment(0)
E
0

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.

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.

Engdahl answered 21/10, 2008 at 22:36 Comment(0)
T
0

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.

Tecumseh answered 19/4, 2009 at 7:36 Comment(0)
R
0

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. I also defined the variables and functions as extern in the header files.

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. In my particular case it makes no difference; but otherwise I couldn't get them to work together.

Roselane answered 23/6, 2009 at 12:58 Comment(0)
J
-3

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.

Jadotville answered 21/10, 2008 at 22:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.