Yes. That's what the keyword "static" is doing in this case. It makes the variable "local" to the compilation unit that it appears in. So each gets it's own copy.
Choose one cpp file to define the variables in. And in Settings.h, make them all "extern".
Sure, that will do. You might want to explicitly initialize it there, too.
Basically, saying something like "extern int extVar;" in a cpp file (perhaps included from a .h file) tells the compiler that the variable exists in another compilation unit and will be resolved by the linker. So you need to actually have the variable defined in one of the cpp files.
can't you make settings.h have an accessor function that just returns either the value ( a little safer) or a reference (typical global variable free for all) to the variable?
you can also wrap a global in a class as a static item so that simply making an instance of the class gives you access to it (directly or via accessors, your pick). This is a little safer, for whatever that is worth. Why are you playing with globals, is this just an example for something else you need to do, or ??
Just including Settings.h in the files that want to access the external variables gives those files access.
That's what the extern keyword does.
Read my last response again.
@tpb
My bad I just ran a driver program to test it, I thing I understand how it works now. Thanks a lot!
@jonnin
Well actually I though about what you said but I don't want to make them into a class because it would be a hassle to use them as arguments and it would make my code significantly longer.
I'm playing around with global variable for a game I'm working on. I have a cpp file with all the global settings for the game to run. Such as key bindings, window, renderer, screen properties etc.
And since I'm loading these variables from a binary file, I only really touch them once. Then they are merely passed as arguments for several functions. So I think that would be "safe" enough.
What makes everybody so concerned about using global variables?
jonnin is right about trying to do without the globals, although a single global object for overall settings can be quite useful. But you should at least gather them together into a single object.
The main fear of global variables is that any function anywhere in the code can change it at any time, making it hard to debug. This is multiplied significantly in multi-threaded code or event driven code. They can also cause name confusion collisions with local variables etc. The bigger the code base, the more trouble they tend to cause.
That said I am not a total nay-sayer, if you have a good reason. But then again, I will do pretty much anything that works ;)
There are at least 3, maybe 4 ways to make globals safer and cleaner as well..
- you can namespace wrap them
- you can do the static class variable trick
- you can wrap *everything related* in one giant class, make the 'global' a member variable, and encapsulate it a bit from other code.
@jonnin
Thanks I will keep that in mind for my work, the more faisable or least annoying method for now, I guess, would be to make a class with all static public member variables.
@tpb
Also I have a new issue. When defining an externconstint I get an error
#include <iostream>
#include "Settings.h"
using namesapce std;
int main()
{
int array[NUMBER]; //ERROR!
//[...]
return 0;
}
1>main.cpp
1> \main.cpp(19): error C2131: expression did not evaluate to a constant
1> \main.cpp(19): note: failure was caused by non-constant arguments or reference to a non-constant symbol
1> \main.cpp(19): note: see usage of 'NUMBER'
Am I doing anything wrong, or am I missing something?
In the first place, they don't need to be extern at all since it doesn't matter if each compilation unit gets it's own "copy" (it would normally disappear from the code, anyway, since it isn't really a variable).
But to keep with the global Settings struct theme, just do this:
1 2 3 4 5 6 7 8 9 10 11 12 13
// settings.h
#ifndef SETTINGS_H_
#define SETTINGS_H_
struct Settings {
staticint a;
staticint b;
staticconstint c = 123; // initialize it here
};
extern Settings settings;
#endif
Actually, you should be able to initialize it here, instead (but you shouldn't do it in both places).
1 2 3 4 5 6
// settings.cpp
#include "settings.h"
int Settings::a = 1;
int Settings::b = 2;
constint Settings::c = 321;
And now that I think about it, I'm not sure why your example doesn't work. I'll try it myself....
Yeah, your example works fine for me (except of course for the misspelled "namespace").
Intesting. Thanks for testing it. When I add -Wall -Wextra -pedantic it complains about a VLA, but that's it. Still, if it was working properly, it shouldn't complain about a VLA, so there's definitely something wrong with it.
But since an extern declaration is not a definition, I don't see why it should matter. As a different example, you can of course do this:
1 2 3 4 5
struct A {
staticconstint n; // no initializer here
};
constint A::n = 123; // done here instead