Sign in to follow this  

multiple definition of X

This topic is 3587 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 need to have a "Gloabls.h" file in which I store some variables like SCREEN_WIDTH, GAME_STATE, DEBUG_LEVEL etc... so that any of my classes can use them. However having included this file in many .cpp files I get a multiple definition problem. I already used #ifndef #define and #endif. Also tried using "extern" but it doesn't work (error still comes up) + I get a warning about the variables being initialized (which they must be). I don't quite understand what extern does and how it works. I'd rather not use commands that have other implications which will require that I handle another problem later on. Is there a simple and elegant way of using the same variables in multiple .h and .cpp files?

Share this post


Link to post
Share on other sites
Don't do that.

Your includes guards don't protect against multiple-definitions (they are per-translation-unit only), see this article. You need to have extern T Variable; in the header, and a definition in one source file (like T Variable = OptionalInitializer) for this to work at all, although you should really try to avoid having to do it at all.

Especially since "globals" headers like that are frequently a bad idea.

Share this post


Link to post
Share on other sites
My personal recommendation is not to use globals in the first place :) Specifically a "Globals.h" master include file.

To answer your question,

Globals should be declared "extern" within the header file, and defined within the source file. For example:
//Globals.h
extern const int SCREEN_WIDTH;
//Globals.cpp
const int SCREEN_WIDTH = 800;
As long as Globals.h has inclusion guards, it should work fine.

I do have to recommend against using this setup, though.

Share this post


Link to post
Share on other sites
Okay I understand now why having global include files is not a good idea, and I'll try to stay away form doing that. However, I still don't get why having global variables is bad thing(TM).

The way I see it, I'll be using SCREEN_WIDTH quite a lot, (a couple hundred times/second) especially in my logic functions. I don't see the advantage of passing it as an argument, even if I only have to do it once in the constructor.

For example, what if I need to change one of these in the middle of running my game? Such as DEBUG_LEVEL. Then I would have to go back and write a whole new function that will change the member variable in each of the classes/functions that I use. It just seems more typing without any benefits.

But anyway, tell me why it's wrong to use global variables since I can't think of any reason why.

Also Crypter,

I can't use "const" in my globals. The whole idea is to be able to change that variable then have all of my functions and classes use the new value without calling any extra function.

Share this post


Link to post
Share on other sites
Quote:
Original post by finky45
The way I see it, I'll be using SCREEN_WIDTH quite a lot, (a couple hundred times/second) especially in my logic functions. I don't see the advantage of passing it as an argument, even if I only have to do it once in the constructor.


Accessing a variable hundred times per second is ridiculously small, and certainly too small to have any kind of performance worries. Think about it: rendering a single 32*32 sprite every frame will be at least a thousand times more costly, performance-wise, than accessing a single variable.

Unless you're working on extremely tight inner loops, don't let micro-optimization considerations affect your design.

Quote:
For example, what if I need to change one of these in the middle of running my game? Such as DEBUG_LEVEL. Then I would have to go back and write a whole new function that will change the member variable in each of the classes/functions that I use. It just seems more typing without any benefits.


You should encapsulate debugging tools in a class of their own, instead of having a modifiable DEBUG_LEVEL variable floating around. Pass that class by reference. You won't have to write new functions to alter that instance's behavior, thanks to the reference semantics.

Quote:
But anyway, tell me why it's wrong to use global variables since I can't think of any reason why.


Global variables generate coupling. Increased coupling makes refactoring and code reuse harder, which results in slower development time.

A clear example? For instance, as they are laid out now, all functions which rely on a viewport width use the SCREEN_WIDTH variable, which means that they all implicitly use the same width. If you wanted to render to a smaller viewport (for instance, to implement a split-screen mode, or to run a game demo in the main menu) or to increase the viewport dimensions for logic purposes (for instance, enemy homing missiles being allowed to stay outside the screen for a certain small distance), then you would have to do some heavy rewriting of these functions so that they can use a different variable. Invariably, changing code always takes longer than writing the code correctly in the first place, so that's a loss of time for you.

A more subtle example? The state management code related to GAME_STATE is certainly quite similar to state-based AI for your opponents, or perhaps to the state-based kernel used in your menus. By having that code explicitly mention GAME_STATE, you prevent its reuse as part of the other state-based systems, which means that you will have to write the same functionality two or three times instead of just one, which is quite wasteful. By making your state-management code parametric, you don't have to write that much additional code (typically one or two additional lines) but you can save one or two rewrites of the repeating functionality.

Share this post


Link to post
Share on other sites
Quote:
Original post by DevFred
Quote:
Original post by finky45
tell me why it's wrong to use global variables

It's impossible to reason about when global state gets changed.


That sentence confuses me.

Maybe I didn't make my problem clear. I want to declare variable X=3 in one place only (preferably in "Globals.h". I want my classes to use X for whatever reason. Then I will make X=4 in a some class. All of my classes should then recognize X being equal to 4.

You know when you declare say "int number=0;" outside of main? Then main knows what it is? How can I do that for all my other .cpp files?

...

Share this post


Link to post
Share on other sites
Quote:
Original post by finky45
That sentence confuses me.


What he means is that, when you look at a global variable after a few weeks, you can't easily tell which functions will change it, when they will change it, and why they will change it.

For instance, suppose that as part of your update step, a function changes the game-state. Would that interrupt the update step? If it does, is it really a great idea to allow a function to skip the execution of an unspecified amount and kind of other functions? If it doesn't, how do you cope with the fact that, as a function is called as part of game state 'A', the game state might have been changed to 'B' or even something else? Will you keep that volatility of the game state in mind whenever you write a function that somehow depends on the current game state?

Share this post


Link to post
Share on other sites
Quote:

The way I see it, I'll be using SCREEN_WIDTH quite a lot, (a couple hundred times/second) especially in my logic functions. I don't see the advantage of passing it as an argument, even if I only have to do it once in the constructor.

globals do not have that much, if any, speed advantage over member variables. The purpose of encapsulating variables behind coherent interfaces that they belong to (the classes) is to help reducing complexity, and make things much easier to modify.

If you use SCREEN_WIDTH alot, and SCREEN_WIDTH is a variable, how can you insure that the value stored in SCREEN_WIDTH is valid? How do you know when it was modified? What happens if you change the name of the variable? How do you know what modifies the variable, and where?

Some of these questions are impossible to know with globals, as any part of the file (or other files, assuming it is externally declared) can access it. If the variable is confined within a single location, only the routines within that same confined place has access to it. This is the bases of encapsulation.

Also, even if your class where the variable is defined has a simple Get() method to retrive your SCREEN_WIDTH variable, it can be declared inline to remove the function call out.

The disadvantages of globals become apparent as your programs get larger.

Share this post


Link to post
Share on other sites
I got it to work the way I wanted based on Crypters solution.

For the sake of argument, I'll try to explain how I am building my game. The GAME_STATE represents the overall state that the game is in. It's an enum. Some states are PAUSED, EXIT etc.. Right now, the only functionality it has is EXIT. If the state is EXIT, then my main will not perform the game loop any longer and will proceed to clean up the game then close.

I want to be able to set the state in my functions which are logic, input, and render. For example if an unrecoverable error occurs in any of my functions then it would tell the game, "okay we need to quit". It sets the STATE to EXIT, reports the error in a file somewhere and then main takes care of the rest.

With proper documentation, I can easily see which function set the state to EXIT, and why. Is it the only way to do it? Obviously not, but it makes sense to me as being easy. The best way? You guys seem to think it's not probably because you have more experience than I do, but I don't see a problem so far.

In my main I have:


cMetalist* metalist = new cMetalist();
cInput* input = new cInput(SCREEN_WIDTH, SCREEN_HEIGHT);
cLogic* logic = new cLogic();
cRender* renderer = new cRender (SCREEN_WIDTH, SCREEN_HEIGHT);

//more crap here

while ( STATE != EXIT )
{
input->Perform( metalist, param1, param2, param3, param4 );
logic->Perform( metalist, param1, param2, param3, param4 );
renderer->Perform( metalist, param1, param2, param3, param4 );
};



See how I have to specify SCREEN_WIDTH and SCREEN_HEIGHT for each class? They need to know that in order to work. Well what happens if I have to change it? Then I need to create get and set functions, then call them in main... etc.. possibly have to recreate the framework objects which I don't even know if they'll work right.

I used to have return types for each of these functions, but that only returned one variable. If I wanted more then I would have to pass parameters. Some were global some were not. The calls would get really long and I hated having to type all that.

The way my game is designed so far, global variables make a lot of sense to me. Its my first game where I try to keep things separate, and this is how I chose to do it. I'm learning from mistakes as I go and rewriting code as I go, and taking forever but I'm learning form it.

Share this post


Link to post
Share on other sites
Quote:
Original post by finky45
I want to be able to set the state in my functions which are logic, input, and render. For example if an unrecoverable error occurs in any of my functions then it would tell the game, "okay we need to quit". It sets the STATE to EXIT, reports the error in a file somewhere and then main takes care of the rest.


Except that it doesn't: this doesn't interrupt the execution of the game loop, it merely marks the current iteration as being the last one. Which means that more code will be executed before the loop ends. For instance, function A detects a fatal error and sets the state to EXIT. Then, function B is called, and relies on something which the fatal error disturbs, and thus you get nasty memory corruption. Then, function C is called, notices that the player wants to pause the game, and sets the state to PAUSE. Then, the game loop finally checks the state, notices that it's PAUSE, and does not interrupt the game.

A good practice when execution should be suspended is to use exceptions, not global variables.

Quote:
With proper documentation, I can easily see which function set the state to EXIT, and why.


True. however, whenever you write a function which does anything within the game, you have to first check if the state is EXIT (just in case another function set it to that) in order to skip execution if it happens. An additional global variable check per function sounds quite annoying to me.

Quote:
See how I have to specify SCREEN_WIDTH and SCREEN_HEIGHT for each class?


Obvious repetition detector beeps at seeing "SCREEN_WIDTH, SCREEN_HEIGHT" twice in the code. This clearly calls for refactoring, for instance as a ScreenDimensions object.

Quote:
Well what happens if I have to change it? Then I need to create get and set functions, then call them in main...


Use the reference to the ScreenDimensions to change the dimensions. Of course, if this is possible, then you have to write your code with this in mind: any code which relies on ScreenDimensions must be able to react to a change of dimensions at any point in time. This, again, sounds quite nasty to me (though I would perhaps rely on a listener system to be notified of changes when they happen).

Quote:
I used to have return types for each of these functions, but that only returned one variable. If I wanted more then I would have to pass parameters.


If a function needs to return several values which are semantically bound together, define a type and return an object of that type.

Quote:
Some were global some were not. The calls would get really long and I hated having to type all that.


If your calls have too many arguments, then you have too much coupling in your design. Hiding the coupling by using global variables won't save you down the line when it strikes back at you. Reduce your coupling now.

Share this post


Link to post
Share on other sites
Quote:
Original post by ToohrVyk
Quote:
cInput* input = new cInput(SCREEN_WIDTH, SCREEN_HEIGHT);


* Alarm bells ringing *

Why does your input class care about screen dimensions?


Input needs to know the dimensions of the game window to calculate an angle formed by the mouse cursor with the center of the screen. This angle is used to point the ship in the right direction: ship->setAngle(angle)

You're right about the main loop. I will have to add a check in each Perform function for GAME_STATE. A little more code to write.

So thats what coupling and refactoring meant...
As my game grows larger I might have to refactor my variables. However I still dislike parameter passing, as I have to write it at least 3 times. Once for the class that changed it, once in a temporary location in main, then once again in the class that receives it.

I have not thought through my entire game before I started writing it, because I can't. There are so many problems and intricacies that I have no clue what they will be because I have never done it before. Ideally I would write everything down on paper before starting, but that requires that I know what to write. I tried doing that then I realized I have no experience and decided to just start coding with the lessons I learned from my previous attempts. It just works for me. When I know everything that is involved in making a game then I'll be able to write something on paper.

Maybe a few weeks/months from now when I run into a problem again, maybe I will go back to passing parameters. I am focusing on keeping my design as simple as possible and trying not to over-engineer. So I will not change it (yet?). I don't find the reasons compelling enough.

Share this post


Link to post
Share on other sites

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