Okay I'm damn fed up with this problem ever since I've been trying to organize a bunch of global variables and functions. I'm organizing the variable/function declarations in a header file and defining them in a separate cpp file. So, Globals.h and Globals.cpp.. I then try and link this both to my main.cpp and my Rabbit.h (which is a custom class I'm making that requires those variables)...I have the header guards and the #pragma once thing... What am I doing wrong? PLEASE HELP! I cannot stand this error anymore.. How should I organize global information and have it not multiply defined?

Recommended Answers

All 10 Replies

Please post the code that you have right now.

Well this is slightly altered since I was trying to fix it but still gives me the damn errors.. Here we go..

Constants.h

#pragma once
#ifndef CONSTANTS_H
#define CONSTANTS_H

#include "SDL.h"
#include "SDL_image.h"
#include "SDL_ttf.h"
#include <iostream>
#include <string>

//constants
const short SCREEN_WIDTH = 640;
const short SCREEN_HEIGHT = 480;
const short SCREEN_BPP = 32;

const short TILE_SIZE = 32;
const short NUM_OF_TILES_X = 20;
const short NUM_OF_TILES_Y = 15;

const short GAME_TIME_IN_SECONDS = 60;

//globals
SDL_Surface* screen = 0;
SDL_Event event;
SDL_Color textColor = { 255, 255, 255 };

//functions
//loads an image and sets it to the same format as the screen - improves performance
SDL_Surface *load_image( std::string filename) 
{
    SDL_Surface* loadedImage = IMG_Load(filename.c_str());
    SDL_Surface* optimizedImage = NULL;
	
    if( loadedImage != NULL )
    {
		//changes to the screen format
        optimizedImage = SDL_DisplayFormat( loadedImage );
        SDL_FreeSurface( loadedImage );

		//any image loaded with RGB(255, 0, 255) will have that colour transparent - QuinnLib standardized 
		if (optimizedImage != NULL)
		{
			Uint32 colorkey = SDL_MapRGB(optimizedImage->format, 255, 0, 255);
			SDL_SetColorKey(optimizedImage, SDL_SRCCOLORKEY, colorkey);
		} 
    }

    return optimizedImage;
}

//blits the source image to the destination at co-ordinates x and y
void apply_surface(int x, int y, SDL_Surface* source, SDL_Surface* destination)
{
	SDL_Rect offset;
	offset.x = x;
	offset.y = y;

	SDL_BlitSurface(source, 0, destination, &offset);
}

//initializes everything, if screen has an error, quits program, otherwise continue 
bool SDL_Initialization(std::string caption)
{
	SDL_Init( SDL_INIT_EVERYTHING );
	screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_SWSURFACE | SDL_ANYFORMAT);
	SDL_WM_SetCaption(caption.c_str(), 0);

	if (!screen)
		return false;
	
	if (TTF_Init() == -1)
		return false;
	
	return true;
}
#endif

Rabbit.cpp

#ifndef RABBIT_H
#define RABBIT_H

#include "Constants.h"

class Rabbit
{
private: 
	int x, y, xVel, yVel;
	SDL_Surface* image;
	int score;
public:
	Rabbit();
	~Rabbit();
	void handle_input();
	void move();
	void show();
};

#endif

main.cpp

#include "Constants.h"
#include <sstream>

using namespace std;

//SDL Surfaces/Events/Fonts
Uint32 timer_start = 0;

int main( int argc, char* args[] )
{
	//if initialization fails, quit program immediately
    if (!SDL_Initialization("Tales of Garzaed"))
		return 1;

	bool quit = false;

	//image loading
	TTF_Font* subfont = TTF_OpenFont( "Zapf.ttf", 16);
	SDL_Surface* image = load_image("rabbit.png");
	SDL_Surface* scoreText = TTF_RenderText_Solid(subfont, "Score: 0", textColor);
	SDL_Surface* background = load_image("background.png");

	//random shit
	timer_start = SDL_GetTicks();
	SDL_Surface* seconds = NULL;

	//title coordinates to blit 
	int title_xvel = 0;
	int title_yvel = 0;
	int title_x = 100;
	int title_y = 50;
	
	//game loop - press x to quit
	while (!quit)
	{
		//determine the event in the queue and deal with it appropriately
		while (SDL_PollEvent( &event ))
		{
			switch(event.type)
			{
			case SDL_QUIT: 
				quit = true;
				break;
			case SDL_KEYDOWN: 
				switch (event.key.keysym.sym)
				{
				case SDLK_LEFT:
					title_xvel -= 2;
					break;
				case SDLK_RIGHT:
					title_xvel += 2;
					break;
				case SDLK_UP:
					title_yvel -= 2;
					break;
				case SDLK_DOWN:
					title_yvel += 2;
					break;
				case SDLK_ESCAPE:
					quit = true;
					break;
				default:
					break;
				}
				break;
			case SDL_KEYUP:
				switch(event.key.keysym.sym)
				{
				case SDLK_LEFT:
					if(title_xvel < 0)
						title_xvel = 0;
					break;
				case SDLK_RIGHT:
                    if(title_xvel > 0 )
                        title_xvel = 0;
                    break;
                case SDLK_UP:
                    if(title_yvel < 0 )
                        title_yvel = 0;
                    break;
                case SDLK_DOWN:
                    if(title_yvel > 0 )
                        title_yvel = 0;
                    break;
                default:
                    break;
                }
                break;
            
            default:
                break;
		}
		}

		title_x += title_xvel;
		title_y += title_yvel;

		stringstream time;
		time << "Timer: " << (SDL_GetTicks() - timer_start) / 1000;

		seconds = TTF_RenderText_Solid( subfont, time.str().c_str(), textColor );

		//draw title image to move around
		SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 0, 0, 0));

		for (int i = 0, n = 0; i < NUM_OF_TILES_X; i++, n += TILE_SIZE)
		{
			for (int j = 0, m = 0; j < NUM_OF_TILES_Y; j++, m += TILE_SIZE)
			{
				apply_surface(n, m, background, screen);
			}
		}
		
		apply_surface(title_x, title_y, image, screen);
		apply_surface(10, 25, seconds, screen);
		apply_surface(10, 5, scoreText, screen);

		SDL_Flip(screen);
	}
	
	SDL_FreeSurface(image);
	SDL_FreeSurface(scoreText);
	SDL_FreeSurface(seconds);
	SDL_FreeSurface(background);
	TTF_CloseFont(subfont);
	TTF_Quit();
    
    return 0;    
}

The list of errors are as follows:
1>Rabbit.obj : error LNK2005: "struct SDL_Surface * __cdecl load_image(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)" (?load_image@@YAPAUSDL_Surface@@V?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z) already defined in main.obj
1>Rabbit.obj : error LNK2005: "void __cdecl apply_surface(int,int,struct SDL_Surface *,struct SDL_Surface *)" (?apply_surface@@YAXHHPAUSDL_Surface@@0@Z) already defined in main.obj
1>Rabbit.obj : error LNK2005: "bool __cdecl SDL_Initialization(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >)" (?SDL_Initialization@@YA_NV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z) already defined in main.obj
1>Rabbit.obj : error LNK2005: "union SDL_Event event" (?event@@3TSDL_Event@@A) already defined in main.obj
1>Rabbit.obj : error LNK2005: "struct SDL_Surface * screen" (?screen@@3PAUSDL_Surface@@A) already defined in main.obj
1>Rabbit.obj : error LNK2005: "struct SDL_Color textColor" (?textColor@@3USDL_Color@@A) already defined in main.obj
1>MSVCRTD.lib(cinitexe.obj) : warning LNK4098: defaultlib 'msvcrt.lib' conflicts with use of other libs; use /NODEFAULTLIB:library
1>C:\Users\Quinn\Documents\Visual Studio 2010\Projects\SDL TEST\Debug\SDL TEST.exe : fatal error LNK1169: one or more multiply defined symbols found

Have you tried to do a clean rebuild of the project? I believe it called rebuild all.

It isn't hard to see where the problem lies, now that we've seen the code. What's going on is that you declare the variables and define several functions in the header itself; this becomes a problem when you then #include said header in more than one compilation unit. To get the desired result, you need to have the functions and variables in the constants.cpp file, and only have function prototypes and extern declarations in the header. So, for constants.h you would have:

#pragma once
#ifndef CONSTANTS_H
#define CONSTANTS_H

#include "SDL.h"
#include "SDL_image.h"
#include "SDL_ttf.h"
#include <string>

//constants
extern const short SCREEN_WIDTH = 640;
extern const short SCREEN_HEIGHT = 480;
extern const short SCREEN_BPP = 32;

extern const short TILE_SIZE = 32;
extern const short NUM_OF_TILES_X = 20;
extern const short NUM_OF_TILES_Y = 15;

extern const short GAME_TIME_IN_SECONDS = 60;

//globals
extern SDL_Surface* screen = 0;
extern SDL_Event event;
extern SDL_Color textColor = { 255, 255, 255 };

SDL_Surface *load_image( std::string filename);
void apply_surface(int x, int y, SDL_Surface* source, SDL_Surface* destination);
bool SDL_Initialization(std::string caption);

#endif

You would basically then put the definitions in constants.cpp instead.

You need to understand how the #include directive works, and how it interacts with the linker. When the preprocessor reads the #include directive (before the compiler itself is run), it immediately replaces the directive with the entire contents of the file being included, then runs through and performs the normal pre-processing as if nothing had been done. So, if you have a file foo.h and a foo.cpp:

#ifndef FOO_H
#define FOO_H

const int quux = 42;

int foo(int x);

#endif
#include "foo.h"
#include "foo.h"

int foo(int x) 
{
    return x * quux;
}

What the compiler actually sees is:

const int quux = 42;

int foo(int x);

int foo(int x) 
{
    return x * quux;
}

As far as the compiler is concerned, this is exactly the file it was passed originally. Notice how the header guards prevent the second copy of the header from actually appearing in the code; the file does indeed get included, but the #ifndef statement means that it is the removed again.

OK, but what happens when you have another file, bar.cpp, that uses the foo() function? Well, let's see:

#include "foo.h"

int main()
{
    printf("%d", foo(23));
}

OK, alll well and good; to the compiler, it looks fine, and compiles correctly. But things don't go so smoothly when the linker gets to it, because both of the compilation units - foo.cpp and bar.cpp - have a definition for quux. This is what causes your multiple definition errors.

That makes sense and I've been doing that as well but it doesn't seem to work.. or maybe you can point out the flaw in this code here which is what it looks with based off the info i just read...

Variables.h

#ifndef VARIABLES_H
#define VARIABLES_H

#include "SDL.h"
#include "SDL_ttf.h"
#include <sstream>

//variables
extern SDL_Surface* screen = SDL_SetVideoMode(640, 480, 32, SDL_SWSURFACE);
extern SDL_Color scoreColor = {255, 255, 255};

extern TTF_Font* font = TTF_OpenFont("Zapf.ttf", 16);
extern int score = 12;
extern std::stringstream display_score;


//functions
void Initialize_Variables();

void draw_text(SDL_Surface* text);

#endif

Variables.cpp

#include "Variables.h"

void Initialize_Variables()
{
	SDL_Init( SDL_INIT_EVERYTHING );
	TTF_Init();
	
	//font = TTF_OpenFont("Zapf.ttf", 16);
	//display_score << "Score: " << score;
}

void draw_text(SDL_Surface* text)
{
	SDL_BlitSurface(text, NULL, screen, NULL);
}

Rabbit.h

#ifndef RABBIT_H
#define RABBIT_H

#include "Variables.h"

class Rabbit
{
private:
	int score;
	SDL_Surface* image;
public:
	Rabbit(void);
	~Rabbit(void);
};

#endif

main.cpp

#include "Variables.h"

int main(int argc, char* args[])
{
	//variables
	Initialize_Variables(); 
	SDL_Surface* scoreText = TTF_RenderText_Solid(font, display_score.str().c_str(), scoreColor);

	SDL_BlitSurface(scoreText, 0, screen, 0);

	//screen refresh
	SDL_Flip(screen);
	SDL_Delay(2000);

	//close
	TTF_Quit();
	SDL_Quit();
	
	return 0;
}

1>Rabbit.obj : error LNK2005: "struct SDL_Color scoreColor" (?scoreColor@@3USDL_Color@@A) already defined in main.obj
1>Rabbit.obj : error LNK2005: "int score" (?score@@3HA) already defined in main.obj
1>Rabbit.obj : error LNK2005: "struct SDL_Surface * screen" (?screen@@3PAUSDL_Surface@@A) already defined in main.obj
1>Rabbit.obj : error LNK2005: "struct _TTF_Font * font" (?font@@3PAU_TTF_Font@@A) already defined in main.obj
1>Variables.obj : error LNK2005: "struct SDL_Color scoreColor" (?scoreColor@@3USDL_Color@@A) already defined in main.obj
1>Variables.obj : error LNK2005: "int score" (?score@@3HA) already defined in main.obj
1>Variables.obj : error LNK2005: "struct SDL_Surface * screen" (?screen@@3PAUSDL_Surface@@A) already defined in main.obj
1>Variables.obj : error LNK2005: "struct _TTF_Font * font" (?font@@3PAU_TTF_Font@@A) already defined in main.obj
1>MSVCRTD.lib(cinitexe.obj) : warning LNK4098: defaultlib 'msvcrt.lib' conflicts with use of other libs; use /NODEFAULTLIB:library
1>main.obj : error LNK2001: unresolved external symbol "class std::basic_stringstream<char,struct std::char_traits<char>,class std::allocator<char> > display_score" (?display_score@@3V?$basic_stringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@A)
1>Variables.obj : error LNK2019: unresolved external symbol "class std::basic_stringstream<char,struct std::char_traits<char>,class std::allocator<char> > display_score" (?display_score@@3V?$basic_stringstream@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@A) referenced in function "void __cdecl Initialize_Variables(void)" (?Initialize_Variables@@YAXXZ)
1>C:\Users\Quinn\Documents\Visual Studio 2010\Projects\Fucking\Debug\Fucking.exe : fatal error LNK1120: 1 unresolved externals

...I could really use any help this problem needs to be solved I've been stuck with it for about two weeks.

Don't initialize the variables in the header file. Initialize them in the .cpp file. In the header file, just declare them.

Alternately you can do this:

//foo.h
struct Constants{
 static const float PI;
 static const float DEGTORAD;
 //...
};
//foo.cpp
const float Constants::PI = 3.1415f;
//...

Your globals should only be const variables. Other than that, you should pass needed variables to whatever that needs it.

Thanks a ton! That worked perfectly.. however now there is the issue of declaring a variable without defining it - this gives me the same multiply defined error...
I declare SDL_Event event; in the header file and when I do not define it I get the error, because it is undefinable really unless an event takes place

Thanks a ton! That worked perfectly.. however now there is the issue of declaring a variable without defining it - this gives me the same multiply defined error...
I declare SDL_Event event; in the header file and when I do not define it I get the error, because it is undefinable really unless an event takes place

Why does that need to be a global?

commented: Why oh why didn't I think to ask that? +7

It's used in both Rabbit.cpp and main.cpp to detect any type of event

It's used in both Rabbit.cpp and main.cpp to detect any type of event

You know you can have more than one instance of SDL_Event right?

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.