Global Variables

I had developed a small application based on WIN API. This application contains 7 projects where some are dependents on others. My problem is that I defined and initiated a global variable x in 1 project. But upon referencing this variable in another project, it appears to be NULL in the time I am sure it must not.

To be clearer, suppose I have 4 projects P1, P2, P3 and P4:
- P1 header (i.e. A1.h) is including P2 header file
- P2 header (i.e. B2.h) is including P3 header file
- P3 header (i.e. C3.h) is including P4 header file
- P4 header is D4.h

A1.h (header file of P1):
1
2
3
4
5
6
#include "B2.h"
#include "D4.cpp" // the global variable is defined in D4.cpp
extern int x;
.
.
.

A1.cpp (cpp file of P1):
1
2
3
4
5
6
7
#include "A1.h"
.
.
printf (. . ., x); // The value of x is NULL
.
.
.

B2.h (header file of P2):
1
2
3
4
#include "C3.h"
.
.
.

C3.h (header file of P3):
1
2
3
4
#include "D4.h"
.
.
.

D4.h (header file of P4):
1
2
3
4
5
#include <windows.h>
extern int x;
.
.
.

D4.cpp (cpp file of P4):
1
2
3
4
5
#include "D4.h"
int x = 100;
.
.
.

The problem appears in A1.cpp file. It is either not referencing the same global variable or the variable is being reset to NULL

Please any ideas.

Regards,
Well right away a red flag is this:

#include "D4.cpp"

You should never be including cpp files.

If you have multiple projects, the typical way to join them is to make all (but one) of them an external library, then you link to that library in any dependent projects.

If you are including a cpp file.. then your code will be using a different copy of the variable as the one in the other project... so changes made to the other project's variable will not be seen in your variable.



Also 7 projects does not scream "small application" to me. Is this really 7 projects or is this 7 source files? Typically 1 project = 1 binary... so if you're just making one application and no separate support libs... you'd only need 1 project.
Disch:
I will tell you the exact steps that I had done so far with no clue:
1- I declared the global variable in D4.h as below (without declaring it in D4.cpp file):
D4.h:
1
2
3
4
5
#include <windows.h>
int x;
.
.
.

P4 was compiled and linked properly.

2- Upon compiling and building P3 (that is dependent on P4 but not accessing x), it gave below linking error:
error LNK2005: "int x" (?x@@3PAXA) already defined in BsolAllForms.obj

3- Then to let P3 know that x is extern variable, I declared it in C3.h file of P3 files as below:
C3.h:
1
2
3
4
5
#include "D4.h"
extern int x;
.
.
.

But still getting the same linking error:
error LNK2005: "int x" (?x@@3PAXA) already defined in BsolAllForms.obj

Later on, after a lot of struggle, I reached the above scenario (in my previous post) and I had included cpp file to let the application bypass the linking error in P1 where I am accessing the global variable. If I don't include D4.cpp (just declaring x as extern in P1 file (i.e. A1.h) without including cpp), I got the below linking error:
error LNK2001: unresolved external symbol.


Regarding "small application", yes they are 7 projects where each contains 5 source files (as average). Each project is a library (DLL) except 1 that generate the exe file.
No further updates on this topic? I need to know exactly how to use the global variables.. they are not working at all
Sorry I totally missed your Nov 2 reply. Whoops.


FWIW, global variables should be avoided since they're usually a design disaster. I'd recommend you reconsider your usage of them here.

That said... if you really must use them...



I'm going to make an analogy between a global variable and a global function. A global function can have both a prototype and a body:

1
2
3
4
5
6
int myfunc();  // prototype

int myfunc()  // body
{
    return 0;
}


Typical usage is... you put the prototype in a header and the body in a cpp file.

1) If you don't put the prototype in the header, then other cpp files will get you an "undeclared identifier" compiler errors when you try to call the function --- the compiler won't know what function it is you're trying to call.

2) If you put the body in the header, then you'll get "multiple definition" linker errors. The linker will see each cpp file as having their own copy of the function and won't know which copy you want to call.

3) If you put the prototype in the header, but DON'T put the body in a cpp file, you'll get "unresolved external" linker errors. The linker will see you calling the function, but since the function has no body it won't be able to call it.


So long story short... the prototype can be in any number of cpp files (via being #included in a header)... but the body must be in exactly ONE (and only one) cpp file.



Global variables are the same way.
 
extern int x;  // variable "prototype" 

 
int x;  // variable "body" 


The "body" in this case actually creates the variable. Whereas the "prototype" merely says 'this variable exists somewhere else'. So conceptually it's the same as with global functions. The same 3 rules listed above apply

So again... long story short.

 
extern int x;  // this goes in a header 

 
int x = 0; // this goes in ONE AND ONLY ONE cpp file 





But again... I really want to stress how terrible of a design global vars usually are. I strongly recommend reconsidering.
I never understand why globals is considered bad design. Its true though that for its not as straight forward as ahbazzi thought they were. All I can add to the answer of Disch is that you want to make sure that .h files are blocked in

1
2
3
4
5
6
7
8
9

#ifndef FILE_H
#define FILE_H

//your code here

#endif



not doing so might also prompt errors


the reason that global variables require extern and everything is because in the C ABI (Application Build Interface) every .cpp file is compiled by itself, that is good for modularity and stuff but is bad for globals, because its not straight forward anymore to have one global to all the different cpp files. What the ABI offers is the functionality of the extern,

basically when you declare a variable "extern" you are telling the compiler that this variable will be discovered in the linking stage which is after all the .cpp files were compiled.
Last edited on
I never understand why globals is considered bad design


There are other reasons... but off the top of my head, here are a few:

- They don't scale well. If your small program has 20 globals and you keep adding more and more as you require new functionality, it isn't long before you're swimming in them.

- They encourage non-modular and non-reusable code. If you write a function which uses a global variable... than that function can ONLY use that global variable. If you write a function which uses a parameter passed in... then your function can work with ANY variable. Trivial but classic example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void damagePlayer(int dmg)
{
    playerHp -= dmg;
    // do other things that happen when the player gets hurt here
}

// vs.

int damageEntity(int hp, int dmg)
{
    hp -= dmg;
    // do other things

    return hp;
}


The first version only works with the player. And only if there's 1 player.

The second version works with the player, enemy, NPC, in-game object, or any additional players/items you add to the game later.

- Smaller scope makes debugging easier. When only a small section of code (like a few functions) has access to any one variable, it's much easier to debug. When something regarding that variable gets messed up... odds are high the problem is somewhere in that small section of code.

With globals, when such a bug occurs... your entire program is suspect because all of it has access to the variable. If your program is several dozen (or even hundred!) cpp files it can be a nightmare to find the bug.
Last edited on
first they scale much better then anything else, you can always group your globals by files relevant to the state that your programming in. When I was working on really big projects(video games) I had a global files for true globals such as screen size and a sub global for each state of the project.

non-modular and non-reusable?? well nothing is reusable untill you turn it into a dll. And you can turn a global variable into a dll no problem, just extern it and mark it (export) or something like that. and by the way, globals is one of the things I never recomend to reuse lightly, whenever you want to make a program similar to another program, before you copy paste it all you want to make sure you understand the structure, architechture, and design of the project. And looking at globals is always easy and straight forward.

concerning debbuging, you are correct. though there are countermesures
first they scale much better then anything else,


How do you figure that? The bigger your project gets, the greater the risk because they're exposed to more code.

you can always group your globals by files relevant to the state that your programming in. When I was working on really big projects(video games) I had a global files for true globals such as screen size and a sub global for each state of the project.


Define "really big". About how many developers? About how many source files?

Something like screen size could be considered global... though personally I wouldn't treat it as one. It's logically a property of the display, and it's not difficult to imagine having multiple displays. It makes more sense to have a class to represent the display. Why would any code other than the display ever need to access the screen size?

Furthermore... no code should (apart from display management code) should be able to directly modify the screen size because that's not a simple "change a variable" action... it requires a fairly complex operation. So not only should that not be a global variable... but it should be a private variable of a class.... with maybe a getter function.

non-modular and non-reusable?? well nothing is reusable untill you turn it into a dll.


You missed the entire point. I didn't [necessarily] mean reusable in other projects... I meant reusable in the same project.

Look at my example again. If you write a function to use a global variable... it only works with that variable. If you write a function to be modular, it works with ANY variable.

A modular function can be reused in multiple situations, whereas you'd have to duplicate the global version for each situation.
Last edited on
I really appreciate your discussion where it contains important information.

basically when you declare a variable "extern" you are telling the compiler that this variable will be discovered in the linking stage which is after all the .cpp files were compiled.


Does the ABI link global variable correctly regardless if it was defined in the dependent or independent project? To make my self much more clear, suppose I have 3 projects P1, P2 and P3:
- P1 is dependent on P2 and P3
- P2 is dependent on P3
- P3 is independent (not depending on any other project)

case 1:
I define global variable in P1 and accessing the global variable in P3

case 2:
I define global variable in P3 and accessing the global variable in P1

Which of the 2 cases will be linked properly and why?

I am asking this question in order to identify the exact problem that I am facing with globals

Thanks in advance for your clarification.

Regards,
Topic archived. No new replies allowed.