Sign in to follow this  

Managing headers correctly within Vis C++ express

This topic is 1973 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

Hey everyone,

I have been following LazyFoo's tutorial series lately to learn a bit about using the SDL library within Visual C++ 2010 Express.

After completing his series, I went on to try and create an application that generates statistics for a character dependent on player input. Eg elf and human races will have different dexterity modifiers etc... Weapon attack will modify your atk modifier etc...

I am having a little linker trouble however. I have split my files up into .h and .cpp files so as to organise everything better. Here are my .h files:

This header is for general includes such as the SDL lib and the std includes
note: I have swapped the > symbols on these includes to " for the purpose of showing my code as the < symbols make whatever is inside them not show up here.
[source lang="cpp"]#ifndef GENHEADERS_H
#define GENHEADERS_H

//General header includes for the STD lib
//As well as other useful utilities

//SDL includes
#include "SDL.h"
#include "SDL_thread.h"
#include "SDL_image.h"
#include "SDL_mixer.h"

//basic utility includes
#include "string"
#include "cmath"
#include "fstream"

using namespace std;

#endif[/source]


This header is for storing my global variables. I have included the General header file here so as I can create SDL defined variables such as SDL_Surface.
[source lang="cpp"]#ifndef GLOBALS_H
#define GLOBALS_H

#include "GenHeaders.h"

bool quit = false;//This manages the game loop
SDL_Surface *screen;//The screen surface(duh)
SDL_Event event;//The event structure

//SDL surfaces
SDL_Surface* background;
SDL_Surface* playerDetailsBG;

//Screen State Variables
enum Screen { playerScreen, detailsScreen };
Screen currentScreen = playerScreen;

#endif[/source]

My constants header file is the same story as the globals, except that it holds onto my constants for me
[source lang="cpp"]#ifndef GENHEADERS_H
#define GENHEADERS_H

//General header includes for the STD lib
//As well as other useful utilities

//SDL includes
#include <SDL.h>
#include <SDL_thread.h>
#include <SDL_image.h>
#include <SDL_mixer.h>

//basic utility includes
#include <string>
#include <cmath>
#include <fstream>

using namespace std;

#endif[/source]

I have a general utilities header to hold global functions such as blitting one surface to another.
[source lang="cpp"]#ifndef UTILITIES_H
#define UTILITIES_H

#include "GenHeaders.h"

//General utility Functions
SDL_Surface *load_image( string fileName );//load an image
void apply_surface( int x, int y, SDL_Surface* source, SDL_Surface* destination, SDL_Rect* clip = NULL );

#endif[/source]

I also have created a header to hold my classes. As you can see I am working on creating a button.
[source lang="cpp"]#ifndef ACORNAPI_H
#define ACORNAPI_H

#include "AcnButton.h"

#endif[/source]

Here is my button header file. This is where the problems arise as the compiler complains that my global variables are already defined in AcnButton.obj

[source lang="cpp"]#ifndef ACNBUTTON_H
#define ACNBUTTON_H

#include "GenHeaders.h"
#include "utilities.h"
#include "globals.h"

///////////////
class AcnButton
///////////////
{
private:
SDL_Rect button;//The range of the background
SDL_Surface *buttonGraphic;//The button graphic
public:
AcnButton( int x, int y, int w, int h );//Constructor
~AcnButton();//Destructor
bool onButton();//Returns true when the given coordinates are within the button
void showButton( SDL_Surface *thisSurface );//applies the button to the given surface
};

#endif[/source]


And my main header.
[source lang="cpp"]#ifndef MAIN_H
#define MAIN_H

#include "AcornAPI.h"
#include "GenHeaders.h"
#include "utilities.h"
#include "globals.h"
#include "Constants.h"

bool initialise();//initialise anything that needs to be
void clean_up();//Frees anything that needs to be
void HandleWindowEvents ();//Handle Window Events
void LoadFiles ();//Load the required Source Files
void ShowBackground();//Show Background Image
void ShowDetails();

#endif[/source]


And my error when I try to compile is:
[source lang="cpp"]1>------ Build started: Project: Acorn, Configuration: Debug Win32 ------
1> AcnButton.cpp
1> Generating Code...
1> Compiling...
1> main.cpp
1> Generating Code...
1>main.obj : error LNK2005: "struct SDL_Surface * background" (?background@@3PAUSDL_Surface@@A) already defined in AcnButton.obj
1>main.obj : error LNK2005: "struct SDL_Surface * playerDetailsBG" (?playerDetailsBG@@3PAUSDL_Surface@@A) already defined in AcnButton.obj
1>main.obj : error LNK2005: "struct SDL_Surface * screen" (?screen@@3PAUSDL_Surface@@A) already defined in AcnButton.obj
1>main.obj : error LNK2005: "union SDL_Event event" (?event@@3TSDL_Event@@A) already defined in AcnButton.obj
1>main.obj : error LNK2005: "bool quit" (?quit@@3_NA) already defined in AcnButton.obj
1>main.obj : error LNK2005: "enum Screen currentScreen" (?currentScreen@@3W4Screen@@A) already defined in AcnButton.obj
1>C:\Users\Me\Documents\Vis C++ Express 2010\Acorn\Debug\Acorn.exe : fatal error LNK1169: one or more multiply defined symbols found
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========[/source]

Now I am assuming it is an error in the header files. Somehow the globals.h is getting included more than once. I have added #ifndef #define #endif to the headers to try and prevent this however.

Does anyone know what I'm missing here?
Perhaps t isn't a problem with the headers, but a problem with the .cpp files?

Please let me know if the headers are fine so as I may pinpoint the source of the issue.

Thank you!

Share this post


Link to post
Share on other sites
You probably want to read [url=http://www.gamedev.net/page/resources/_/technical/general-programming/organizing-code-files-in-c-and-c-r1798]this article on organizing code files in C and C++[/url]. In particular look at problem 4 in the article.

Share this post


Link to post
Share on other sites
[quote name='Alismuffin' timestamp='1343094603' post='4962437']
note: I have swapped the > symbols on these includes to " for the purpose of showing my code as the < symbols make whatever is inside them not show up here.
[/quote]
GameDev's [ source] tags eat HTML characters and do more harm than good. I wish GameDev would just get rid of the broken [ source] tag. Use [ code] tags instead. They eat your code less.

[quote name='Alismuffin' timestamp='1343094603' post='4962437']
Does anyone know what I'm missing here?
Perhaps t isn't a problem with the headers, but a problem with the .cpp files?
[/quote]
The problem is that there are multiple definitions of the global variables. Remember, #include just does a dumb copy 'n' paste of the text. So each .cpp file that includes Globals.h gets a copy 'n' paste of the contents of Globals.h in it. This means that each source file gets it's own globals, which is bad. The linker comes along and starts linking things, and sees that all these translation units (compiled .cpp files) have global variables, and that each translation unit's global variables are the same names. Somehow, the linker has to merge all these translation units into one executable, but it can't because the global variables are having naming conflicts.

So how do you fix it?
Declare the globals as [url="http://www.learncpp.com/cpp-tutorial/42-global-variables/"]extern[/url] in the header, and then give them actual definitions (without extern) in [b]one[/b] .cpp file. The extern keyword makes it so that the variable isn't actually defined, it just tells the compiler that there's a variable with this name that exists, but it has to figure out where it exists at the linking stage. The linker then only gets one copy of these variables (because you put the actual definitions in only [b]one[/b] .cpp file), and then it can go through all the translation units and replace the "externed" global variables with references to the proper, real global variables.

Share this post


Link to post
Share on other sites

This topic is 1973 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