trouble with header and global vars

closed account (zwA4jE8b)
I separated my game classes into different header and cpp files.
gamengine.h gamengine.cpp levelengine.h levelengine.cpp snakengine.h snakengine.cpp and snakemain.cpp

The way I have it set up so far is that
snakemain includes gamengine.h
gamengine.h includes levelengine.h and snakengine.h

The game class utilizes both level and snake class.
snakemain takes care of all the windows stuff, i.e. message loop.

The following variables are used in more than one class. I am having trouble compiling because I keep getting lnk2005 object already exists errors.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#define screen_width 800
#define screen_height 600

#include <Windows.h>
#include <vector>
#include <ctime>
#include <sstream>
#include <string>
#include <fstream>

const DWORD _up = 0x57, _down = 0x53, _left = 0x41, _right = 0x44, _pause = 0x50,
			_yes = 0x59, _no = 0x4E, _esc = 0x1B;
const int _rectwidth = 10, _rectheight = 10, _bordertop = 5, _borderleft = 5,
		  _borderbottom = screen_height - 65, _borderright = screen_width - 9;

COLORREF _blue = RGB(0,0,255);
COLORREF _red = RGB(255,0,0);
COLORREF _white = RGB(255,255,255);
COLORREF _black = RGB(0,0,0);
COLORREF _green = RGB(0,255,0);
COLORREF _purple = RGB(200,50,200);
HBRUSH _bluebrush = CreateSolidBrush(_blue);
HBRUSH _whitebrush = CreateSolidBrush(_white);
HBRUSH _blackbrush = CreateSolidBrush(_black);
HBRUSH _greenbrush = CreateSolidBrush(_green);

std::string convstr(const int& t){std::stringstream itoa; itoa << t; return itoa.str();}
std::vector<RECT> _foodgrid, _obstaclegrid;


Where would I place these variables, function, and vectors?

If more code is needed please let me know.

I have yet to make a project this large. Originally I just had two files. snakemain and snakengine.
Last edited on
closed account (zb0S216C)
Place your global declarations within a namespace[1].

References:
[1]http://www.cplusplus.com/doc/tutorial/namespaces/


Wazzak
Last edited on
closed account (zwA4jE8b)
should I put all the above code - the global stuff in a header

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#ifndef H_BASE
#define H_BASE
#define screen_width 800
#define screen_height 600

#include <Windows.h>
#include <vector>
#include <ctime>
#include <sstream>
#include <string>
#include <fstream>

namespace global
{

	const DWORD _up = 0x57, _down = 0x53, _left = 0x41, _right = 0x44, _pause = 0x50,
				_yes = 0x59, _no = 0x4E, _esc = 0x1B;
	const int _rectwidth = 10, _rectheight = 10, _bordertop = 5, _borderleft = 5,
			  _borderbottom = screen_height - 65, _borderright = screen_width - 9;

	COLORREF _blue = RGB(0,0,255);
	COLORREF _red = RGB(255,0,0);
	COLORREF _white = RGB(255,255,255);
	COLORREF _black = RGB(0,0,0);
	COLORREF _green = RGB(0,255,0);
	COLORREF _purple = RGB(200,50,200);
	HBRUSH _bluebrush = CreateSolidBrush(_blue);
	HBRUSH _whitebrush = CreateSolidBrush(_white);
	HBRUSH _blackbrush = CreateSolidBrush(_black);
	HBRUSH _greenbrush = CreateSolidBrush(_green);

	std::string convstr(const int& t){std::stringstream itoa; itoa << t; return itoa.str();}
	std::vector<RECT> _foodgrid, _obstaclegrid;
}
#endif

Do I need the ifndef?


Also: do I include this header in my other .cpp files and write

global::needed stuff here
Last edited on
closed account (zb0S216C)
Yes. The ifndef is a header guard. Always use it within headers.

CreativeMFS wrote:
Also: do I include this header in my other .cpp files and write
global::needed stuff here

Yes.


Wazzak
Last edited on
closed account (zwA4jE8b)
I am still getting lnk2005 errors.

1>levelengine.obj : error LNK2005: "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl global::convstr(int const &)" (?convstr@global@@YA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@ABH@Z) already defined in gamengine.obj
1>levelengine.obj : error LNK2005: "unsigned long global::_blue" (?_blue@global@@3KA) already defined in gamengine.obj
1>levelengine.obj : error LNK2005: "unsigned long global::_red" (?_red@global@@3KA) already defined in gamengine.obj
1>levelengine.obj : error LNK2005: "unsigned long global::_white" (?_white@global@@3KA) already defined in gamengine.obj
1>levelengine.obj : error LNK2005: "unsigned long global::_black" (?_black@global@@3KA) already defined in gamengine.obj
1>levelengine.obj : error LNK2005: "unsigned long global::_green" (?_green@global@@3KA) already defined in gamengine.obj
1>levelengine.obj : error LNK2005: "unsigned long global::_purple" (?_purple@global@@3KA) already defined in gamengine.obj
1>levelengine.obj : error LNK2005: "struct HBRUSH__ * global::_bluebrush" (?_bluebrush@global@@3PAUHBRUSH__@@A) already defined in gamengine.obj
1>levelengine.obj : error LNK2005: "class std::vector<struct tagRECT,class std::allocator<struct tagRECT> > global::_foodgrid" (?_foodgrid@global@@3V?$vector@UtagRECT@@V?$allocator@UtagRECT@@@std@@@std@@A) already defined in gamengine.obj
1>levelengine.obj : error LNK2005: "struct HBRUSH__ * global::_blackbrush" (?_blackbrush@global@@3PAUHBRUSH__@@A) already defined in gamengine.obj
1>levelengine.obj : error LNK2005: "class std::vector<struct tagRECT,class std::allocator<struct tagRECT> > global::_obstaclegrid" (?_obstaclegrid@global@@3V?$vector@UtagRECT@@V?$allocator@UtagRECT@@@std@@@std@@A) already defined in gamengine.obj
1>levelengine.obj : error LNK2005: "struct HBRUSH__ * global::_greenbrush" (?_greenbrush@global@@3PAUHBRUSH__@@A) already defined in gamengine.obj
1>levelengine.obj : error LNK2005: "struct HBRUSH__ * global::_whitebrush" (?_whitebrush@global@@3PAUHBRUSH__@@A) already defined in gamengine.obj
1>snakemain.obj : error LNK2005: "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl global::convstr(int const &)" (?convstr@global@@YA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@ABH@Z) already defined in gamengine.obj
1>snakemain.obj : error LNK2005: "unsigned long global::_blue" (?_blue@global@@3KA) already defined in gamengine.obj
1>snakemain.obj : error LNK2005: "unsigned long global::_red" (?_red@global@@3KA) already defined in gamengine.obj
1>snakemain.obj : error LNK2005: "unsigned long global::_white" (?_white@global@@3KA) already defined in gamengine.obj
1>snakemain.obj : error LNK2005: "unsigned long global::_black" (?_black@global@@3KA) already defined in gamengine.obj
1>snakemain.obj : error LNK2005: "unsigned long global::_green" (?_green@global@@3KA) already defined in gamengine.obj
1>snakemain.obj : error LNK2005: "unsigned long global::_purple" (?_purple@global@@3KA) already defined in gamengine.obj
1>snakemain.obj : error LNK2005: "struct HBRUSH__ * global::_bluebrush" (?_bluebrush@global@@3PAUHBRUSH__@@A) already defined in gamengine.obj
1>snakemain.obj : error LNK2005: "class std::vector<struct tagRECT,class std::allocator<struct tagRECT> > global::_foodgrid" (?_foodgrid@global@@3V?$vector@UtagRECT@@V?$allocator@UtagRECT@@@std@@@std@@A) already defined in gamengine.obj
1>snakemain.obj : error LNK2005: "struct HBRUSH__ * global::_blackbrush" (?_blackbrush@global@@3PAUHBRUSH__@@A) already defined in gamengine.obj
1>snakemain.obj : error LNK2005: "class std::vector<struct tagRECT,class std::allocator<struct tagRECT> > global::_obstaclegrid" (?_obstaclegrid@global@@3V?$vector@UtagRECT@@V?$allocator@UtagRECT@@@std@@@std@@A) already defined in gamengine.obj
1>snakemain.obj : error LNK2005: "struct HBRUSH__ * global::_greenbrush" (?_greenbrush@global@@3PAUHBRUSH__@@A) already defined in gamengine.obj
1>snakemain.obj : error LNK2005: "struct HBRUSH__ * global::_whitebrush" (?_whitebrush@global@@3PAUHBRUSH__@@A) already defined in gamengine.obj
1>snakengine.obj : error LNK2005: "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl global::convstr(int const &)" (?convstr@global@@YA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@ABH@Z) already defined in gamengine.obj
1>snakengine.obj : error LNK2005: "unsigned long global::_blue" (?_blue@global@@3KA) already defined in gamengine.obj
1>snakengine.obj : error LNK2005: "unsigned long global::_red" (?_red@global@@3KA) already defined in gamengine.obj
1>snakengine.obj : error LNK2005: "unsigned long global::_white" (?_white@global@@3KA) already defined in gamengine.obj
1>snakengine.obj : error LNK2005: "unsigned long global::_black" (?_black@global@@3KA) already defined in gamengine.obj
1>snakengine.obj : error LNK2005: "unsigned long global::_green" (?_green@global@@3KA) already defined in gamengine.obj
1>snakengine.obj : error LNK2005: "unsigned long global::_purple" (?_purple@global@@3KA) already defined in gamengine.obj
1>snakengine.obj : error LNK2005: "struct HBRUSH__ * global::_bluebrush" (?_bluebrush@global@@3PAUHBRUSH__@@A) already defined in gamengine.obj
1>snakengine.obj : error LNK2005: "class std::vector<struct tagRECT,class std::allocator<struct tagRECT> > global::_foodgrid" (?_foodgrid@global@@3V?$vector@UtagRECT@@V?$allocator@UtagRECT@@@std@@@std@@A) already defined in gamengine.obj
1>snakengine.obj : error LNK2005: "struct HBRUSH__ * global::_blackbrush" (?_blackbrush@global@@3PAUHBRUSH__@@A) already defined in gamengine.obj
1>snakengine.obj : error LNK2005: "class std::vector<struct tagRECT,class std::allocator<struct tagRECT> > global::_obstaclegrid" (?_obstaclegrid@global@@3V?$vector@UtagRECT@@V?$allocator@UtagRECT@@@std@@@std@@A) already defined in gamengine.obj
1>snakengine.obj : error LNK2005: "struct HBRUSH__ * global::_greenbrush" (?_greenbrush@global@@3PAUHBRUSH__@@A) already defined in gamengine.obj
1>snakengine.obj : error LNK2005: "struct HBRUSH__ * global::_whitebrush" (?_whitebrush@global@@3PAUHBRUSH__@@A) already defined in gamengine.obj
1>C:\Visual Studio 2010\C++\0 - Good Projects\Snake - Graphical\Debug\Snake - Graphical.exe : fatal error LNK1169: one or more multiply defined symbols found
1>
1>Build FAILED.
closed account (zb0S216C)
Are any of your files including this header module more than once?

As extra protection, add #pragma once at the top of your header, just below the #defines.
Note that #pragma is only valid on Microsoft compilers.

Wazzak
The include guard doesn't prevent this problem. It prevents a header file being included multiple times in the same source file/translation unit. To get multiply defined symbols, you need only define them once in each of two or more source files/translation units.

Global variables should be put in a single source file, and in the header file merely declare them as extern:
 
extern int foo;

which tells the link that the symbol 'foo' is going to be defined in another translation unit.

(This isn't an issue with functions, as they are extern by default).

Note: I suggest you don't use compiler macros for program constants such as window width and height. They are, among other things, unaffected by scope and, in particular, namespaces. Consider this:
 
const unsigned Width = 800;

rather than this:
 
#define Width 800 


-Xander

EDIT: While include guards don't solve this problem, they should be put in to avoid other problems. Don't misinterpret my post and remove them ;)
Last edited on
closed account (zwA4jE8b)
I think I am in over my head with this one.
yes i have the base.h is included in each of my .cpp files. I understand that is why I am getting the error. but if I do not include it then the brushes and vectors are undefined.

I am just going to make separate variables specific to each class instead of trying to make them global.
closed account (zwA4jE8b)
should I try to stay away from global variables and just pass them through the functions?
Last edited on
Basically, if you define a variable in multiple files (which you are as the header file is included in multiple files), then it is multiply defined, which is not allowed.

Thus, you avoid this by only putting forward declarations of variables with the 'extern' keyword in header files. Then all you have to do is define the variables in one source file. When the compiler compiles the other source files, it will not be able to find a definition of the variables, which would be a problem. However, it sees the 'extern' keyword, and realises that the definitions are elsewhere, so it does not complain.

Then when the linker combines all the compiled source files, everything works just fine, as the source files using the variables are combined the with the source file which defines them.
closed account (zwA4jE8b)
So my BASE.h should look like this...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#ifndef H_BASE
#define H_BASE
#include <Windows.h>
#include <vector>
#include <ctime>
#include <sstream>
#include <string>
#include <fstream>

	const int screen_width =  800;
	const int screen_height = 600;

	const DWORD _up = 0x57, _down = 0x53, _left = 0x41, _right = 0x44, _pause = 0x50,
				_yes = 0x59, _no = 0x4E, _esc = 0x1B;
	const int _rectwidth = 10, _rectheight = 10, _bordertop = 5, _borderleft = 5,
			  _borderbottom = screen_height - 65, _borderright = screen_width - 9;

	COLORREF _blue = RGB(0,0,255);
	COLORREF _red = RGB(255,0,0);
	COLORREF _white = RGB(255,255,255);
	COLORREF _black = RGB(0,0,0);
	COLORREF _green = RGB(0,255,0);
	COLORREF _purple = RGB(200,50,200);
	HBRUSH _bluebrush = CreateSolidBrush(_blue);
	HBRUSH _whitebrush = CreateSolidBrush(_white);
	HBRUSH _blackbrush = CreateSolidBrush(_black);
	HBRUSH _greenbrush = CreateSolidBrush(_green);

	std::string convstr(const int& t){std::stringstream itoa; itoa << t; return itoa.str();}
	std::vector<RECT> _foodgrid, _obstaclegrid;
#endif 


and for example in snakengine.cpp I...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <Windows.h>
#include <vector>
#include "snakengine.h"

extern int _rectwidth, _rectheight;
extern DWORD _up, _down, _left, _right;
extern HBRUSH _bluebrush, whitebrush;

//Snake class defs
snake::snake(int _level):_lvl(_level), _length(_lvl*8), _direction(NULL), _counter(0), _ret('n'), _tocount((_lvl * 8) - 1){}

void snake::init_snake()
{
	_segments.resize(0);
	for(i = 0; i < _length; i++)
	{
		RECT _newseg = {390, 290, 390 + _rectwidth, 290 + _rectheight};
		_segments.push_back(_newseg);
	}
};
void snake::show_head(const HDC& hDC)
{
		FillRect(hDC, &_segments[0], _bluebrush); 
}


Wrong way round =P The ones without 'extern' are the actual definitions, which should occur only once, e.g. in a particular source file. On the other hand the ones with 'extern', you can view merely as forward declarations to tell the compiler that the symbols will be resolved by the linker. You can declare the same variable using 'extern' as many times as you like, e.g. in a header file to be included in multiple source files.
Are you including the header file in multiple cpp files?

If so, the header file needs to declare the variables (as extern)

1
2
3
4
5
6
7
8
9
10
extern COLORREF _blue
extern COLORREF _red
extern COLORREF _white;
extern COLORREF _black;
extern COLORREF _green;
extern COLORREF _purple;
extern HBRUSH _bluebrush;
extern HBRUSH _whitebrush;
extern HBRUSH _blackbrush;
extern HBRUSH _greenbrush;


And you need their definitions in one of the cpp files

1
2
3
4
5
6
7
8
9
10
COLORREF _blue = RGB(0,0,255);
COLORREF _red = RGB(255,0,0);
COLORREF _white = RGB(255,255,255);
COLORREF _black = RGB(0,0,0);
COLORREF _green = RGB(0,255,0);
COLORREF _purple = RGB(200,50,200);
HBRUSH _bluebrush = CreateSolidBrush(_blue);
HBRUSH _whitebrush = CreateSolidBrush(_white);
HBRUSH _blackbrush = CreateSolidBrush(_black);
HBRUSH _greenbrush = CreateSolidBrush(_green);


I would generally initialize the variables in WM_CREATE and displose of them in WM_DESTROY.

The consts should be OK in the header.
Actually, you might want to make the COLORREF values all const?
Provided RGB is a macro (or a C++0x constexpr function...) and also provided that they are not later changed (I'm guessing not), then they should indeed be made const.
closed account (zwA4jE8b)
Thanks guys, but I think I need to practice this with something small then apply it to my game. It is becoming a mess.
closed account (zwA4jE8b)
with your help and another online tutorial I have it. My only problem now is my switch/case statements cause errors because it wants constant expressions.

declaration in .h file
1
2
extern const DWORD _up , _down, _left, _right, _pause,
			_yes, _no, _esc;


definition in .cpp file
1
2
const DWORD _up = 0x57, _down = 0x53, _left = 0x41, _right = 0x44, _pause = 0x50,
			_yes = 0x59, _no = 0x4E, _esc = 0x1B;


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
case WM_KEYDOWN:
		{
			switch (wParam)
			{
			case _up:
			case _down:
			case _left:
			case _right:
				_game.game_input(wParam);
				break;
			case _pause:
				_game.game_setstate('t');
				break;
			case _esc:
				_game.game_setstate('o');
				break;
			}
			return 0;
		} break;


_up, _down, _left, _right etc. etc are causing errors.

Is there a way around this. everything else seems to work now though.
closed account (zwA4jE8b)

externvars.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#ifndef H_externvars
#define H_externvars

#include <windows.h>
#include <vector>
#include <sstream>
#include <string>
#include <ctime>
#include <fstream>

extern const int screen_width;
extern const int screen_height;

extern const int _rectwidth, _rectheight, _bordertop, _borderleft,
		  _borderbottom, _borderright;

const DWORD _up = 0x57, _down = 0x53, _left = 0x41, _right = 0x44, _pause = 0x50,
			_yes = 0x59, _no = 0x4E, _esc = 0x1B;

extern const COLORREF _blue;
extern const COLORREF _red;
extern const COLORREF _white;
extern const COLORREF _black;
extern const COLORREF _green;
extern const COLORREF _purple;
extern const HBRUSH _bluebrush;
extern const HBRUSH _whitebrush;
extern const HBRUSH _blackbrush;
extern const HBRUSH _greenbrush;

extern std::vector<RECT> _foodgrid, _obstaclegrid;
#endif 


externvars.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include "externvars.h"

const int screen_width =  800;
const int screen_height = 600;

const int _rectwidth = 10, _rectheight = 10, _bordertop = 5, _borderleft = 5,
		  _borderbottom = screen_height - 65, _borderright = screen_width - 9;

const COLORREF _blue = RGB(0,0,255);
const COLORREF _red = RGB(255,0,0);
const COLORREF _white = RGB(255,255,255);
const COLORREF _black = RGB(0,0,0);
const COLORREF _green = RGB(0,255,0);
const COLORREF _purple = RGB(200,50,200);
const HBRUSH _bluebrush = CreateSolidBrush(_blue);
const HBRUSH _whitebrush = CreateSolidBrush(_white);
const HBRUSH _blackbrush = CreateSolidBrush(_black);
const HBRUSH _greenbrush = CreateSolidBrush(_green);

std::vector<RECT> _foodgrid, _obstaclegrid;
What you have written will certainly now work. However, I've done some experiments and it appears that (for GCC at least) you can in fact leave the 'const' ones in the header file without 'extern' ( as you have done for '_up', '_down', etc).
closed account (zwA4jE8b)
Thank you guys for your help.
Topic archived. No new replies allowed.