Sign in to follow this  

Multiple definitions

This topic is 4559 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I've got three files: main.cpp, headers.h, and functions.h. Pretty original, right? Okay, so, as I understand it, I need the following code around the contents of headers.h:
#ifndef INC_HEADERS_H
#define INC_HEADERS_H

//...

#endif


So, if I'm getting this correctly, which I'm not, it should check to see if it's already defined, and then if it's not, it goes ahead and executes the code. Which should take care of the multiple definitions, right? but I still get errors like this: functions.cpp C:\Dev-Cpp\Programs\Allegro\Ping\functions.o(.bss+0x0) multiple definition of `p1position' Thanks for any help.

Share this post


Link to post
Share on other sites
It is not that simple. First off, code is only executed if you run the program after it has been compiled. The compiler itself just compiles your code; it does not run it.

Second, you should discern declarations from definitions. A declaration just says what a program element (class, function, variable, etc) looks like from the outside. The definition then gives how it really is. Many times you can ommit the declaration and definne something at once. Some examples first:

// Declaration only
void f( int i );

// Definition and declaration
void f( int i )
{
}


You may repeat declarations as much as you like, as long as they are the same. That is why the previous example is ok -- f is declared twice. But you may only define any symbol just once.

Having cleared that up, a multiple definitions error refers to a symbol being defined twice. For example, a global variable positions may be in two files somehwere in the project, leaving the compiler in the blue about which one is intended.

In your case, I presume you have the variable only once in one header file. The guards do prevent in general mixing the symbols, however in the following case this process fails. Assume a header file header.h which, within guards, defines a variable positions:

// Headers.h
#ifndef _HEADERS_H_
#define _HEADERS_H_
int positions;
#endif


Now assume two source files, which both independently include headers.h. In both files, at include time, the guard is not defined and the file is included. This leaves your program with two definitions of the positions variable!

So now for the solution (wee this is a long post). You should generally put only declarations in header files, and definitions in source files. So, in the above example, employ the following scheme:

// Headers.h
#ifndef _HEADERS_H_
#define _HEADERS_H_

// Just declare positions
extern int positions;

#endif



// Headers.cpp
#include "Headers.h"

// Define positions
int positions;


This will make sure all source files referring to headers.h, agree about the single positions symbol, which is defined only in headers.cpp.

Good luck; greetz Illco.

Share this post


Link to post
Share on other sites
To understand why header guards can avoid multiple defintion errors, you have to consider the one definition rule.

Quote:
3.2.1 ISO/IEC 14882 C++ Standard
No translation unit shall contain more than one definition of any variable, function, class type, enumeration type or template.


(A translation unit is a .cpp file after the preprocessor has been executed on it)

Header guards are used to prevent multiple definitions of whatever they contain within a translation unit, but they do not prevent multiple definitions across multiple translation units.

This is only a problem if the standard forbids multiple definitions of the contained objects within a program, and not just within a translation unit.

A common example of something that can only be defined once within a program and within a translation unit is a non-inline non-template function

Quote:
3.2.3 ISO/IEC 14882 C++ Standard
Every program shall contain exactly one definition of every noninline function or object that is used in that program;



#ifndef guard
#define guard

void function(){}

#endif





Here the non-inline function function() has been put in header guards. This prevents it from being defined multiple times within one translation unit, but not within a program, which is a problem in this case as we are only allowed one definition within a program.

On the other hand you can have multiple definitions of inline functions in a program

Quote:
3.2.3
An inline function shall be defined in every translation unit in which it is used.




#ifndef guard
#define guard

inline void function(){}

#endif





In this case we are allowed to have more than one definition of the inline function function() within a program, but again we are only allowed one definition within a translation unit. The header guards prevent the function from being defined more than once within a translation unit, but not within a program. But since we are allowed more than one definition in a program, that is not a problem.

So in conclusion, you use header guards to prevent things from being defined more than once within a translation unit, not within a program. So whether they solve multiple definition errors depends on whether or not the object that is encapsulated within them can be defined more than once within a program, which the majority of things can be.

Here is a brief list of things that can be
classes
class templates
function templates
inline functions
variables with internal linkage

Some things that can't be defined multiple times within a program
non-inline non-template functions
variables with external linkage

Share this post


Link to post
Share on other sites
Okay, let me elaborate a little on what I've got, and what I'm trying to do.
In headers.h I have a some function prototypes and variable declarations. main.cpp calls headers.h and then assigns bitmaps to the BITMAP pointers defined in headers.h (I'm using Allegro). Then main.cpp calls my game loop, which calls several functions prototyped in headers.h and declared (If that's the right term?) in functions.cpp, and those functions modify some of the variables in headers.h.

How should I best organize this? Is it okay to define variables in headers.h, or should I assign values to them all in main.cpp?
Quote:

// Headers.h
#ifndef _HEADERS_H_
#define _HEADERS_H_

// Just declare positions
extern int positions;

#endif



// Headers.cpp
#include "Headers.h"

// Define positions
int positions;

How is it defining positions in headers.cpp?
Why couldn't you just define it in headers.h and use it in headers.cpp?

Thanks for all the help.

Share this post


Link to post
Share on other sites
Quote:

How is it defining positions in headers.cpp?

This is how you define a variable:

int positions;

Since it is done in headers.cpp it defines positions in headers.cpp. Nothing more, nothing less.

Quote:

Why couldn't you just define it in headers.h and use it in headers.cpp?

As opposed to declarations, definitions are allowed only once. If a variable is defined in a header file, and it is included in various source files, the variable will be defined multiple times.

Think about the following sample. We have headers.h as you had it, thus with the definition of a variable. Now we see our first source file, one.cpp:

// One.cpp
#include "Headers.h"

What the compiler (or actually the pre-processor) does is the following. The compiler starts from blank since this is a new source file (the result of compiling each source file will not be linked until the linking fase). It sees the guard in headers, and it sees it for the first time in this context. Hence the guard passes and the variable is defined. Nice.

Now the next file is processed:

// Two.cpp
#include "Headers.h"

What the compiler (or actually the pre-processor) does is the following. The compiler starts from blank since this is a new source file (the result of compiling each source file will not be linked until the linking fase). It sees the guard in headers, and it sees it for the first time in this context. Hence the guard passes and the variable is defined. Nice.

Now the linker links one.obj and two.obj together. Both have the variable defined. Clash! You can only have one definition of a variable.

Share this post


Link to post
Share on other sites
Okay, so how do I get around this? Do I have to use extern and then assign values to my variables in main? If I use extern, will I then be able to access those values with my functions.cpp file without problems?
I'm about ready to give up this whole organization thing and just stick all my stuff in one file...

Share this post


Link to post
Share on other sites
A good idea is, indeed, to declare the variables only in the header file, using extern and implement them in one of the source files. You can be sure that the same instance is used, since it is the only one you provide.

If source organisation is a problem, try to look up some articles about it. There are a few on gamedev and some more via the web. Next, I saw you used names 'headers.h' and 'functions.h'. This make is it no easier; these names are nonsensical as any header is a header and most of them contain functions. You'd be better of dividing your code by means of functionality; giving headers like 'vectors.h' and 'logic.h', for example.

You also had some difficulty with declaration and definition and keeping them together. A good approach would be to have one header file and one implementation file (.h and .cpp) for each unit, named with the same name. Then you can be confident that the declaration made in x.h are implemented in x.cpp.

Greetz,

Illco

Share this post


Link to post
Share on other sites

This topic is 4559 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this