I have a C++ solution in which there is a global variable which I want to be accessible across projects in the solution file. I know this is not recommended but what is the best way to do this?
Define the variable once, in the file that originally has the global variable and declare the variable extern in every file that uses it.
File 1:
int GlobalVariable;
int main(int argc, char *argv[]) {
// blablabla
}
File 2:
extern int GlobalVariable;
int somefunc(void) {
// blablabla
}
File 3:
extern int GlobalVariable;
// blablabla
All projects in a solution - ie you're building several dlls, grouped togetehr in a solution?
If that's the case then you have the problem that the a global in one dll cannot easily be read by another dll. You will need write the global to shared memory and have all dlls read from there.
An alternative aproach is easy: create a dll jsut to hold your shared variables and wrap them in a pragma. eg from this link:
#pragma data_seg (".myseg")
int i = 0;
char a[32]n = "hello world";
#pragma data_seg()
then each of your different dlls can link with the 'data dll', the data dll will contain a single instance of the variables no matter how many times its loaded or in which process. Performance counters use this technique to quickly pass data counters between the process that generates the data and perfmon.exe that reads and displays it.
There is a difference between Translation Unit and Project (specifically in Visual Studio).
In C and C++ you can make a global variable only accessible from the file in which it's declared by using the static keyword in front of the declaration. Globals that don't use the static keyword are accessible from any C or C++ file compiled into the program.
But frankly your question is not clear. When you say Global there can be lots of perspectives to it, as Wikipedia says in the article on Global Variables:
The C language does not use the term global, though in a small program contained in a single file it is possible to get the same effect by declaring a variable outside all functions (see below). However, such a variable should be called external, not global, since its scope is limited to the single file.
But, you may go through these links to see if you can solve the your specific problem:
Global variables/functions across different projects
Shared global variable in C++ static library
How to implement process-global variable in C++
Related
Well, I'm learning C++ and never really learned how to do stuff that is not OO.
I'm trying to get a bit more experience coding in C style.
GobalInformation.h
#pragma once
#ifndef GLOBALINFORMATION_H
#define GLOBALINFORMATION_H
#include "MapInformation.h"
namespace gi {
MapInformation mapInf;
};
#endif
I would like to be able to access gi::mapInf from every header and cpp in my project. Right now I'm including globalinformation.h in every header, so I'm getting linker errors with multiple definitions.
How can I work around the problem?
In header file only do
namespace gi {
extern MapInformation mapInf;
};
In CPP file provide the actual definition.
namespace gi {
MapInformation mapInf;
};
It will work as you intend.
If you are using the MapInformation across dynamic link library boundaries you might have to link against the library that includes the definition cpp file. Also on Window you might have to use dllimport/dllexport
Be aware that having globals in multiple compilation units can easily lead to order-of-initialization problems. You may wish to consider replacing each global with a function that returns a reference. In your case, put this in one cpp file and declare it in the header:
namespace gi {
MapInformation& getMapInf()
{
static MapInformation result;
return result;
}
}
Global variables are C, but namespaces are C++. There is a good discussion on using global variables and how they can be replaced by Singleton pattern: Globals and Singletons
And here is a simple sample: CPP/Classes/Singleton
Perhaps a better solution is to create a global object that contains all your global data. Then pass a smart pointer to the classes that actually need to access this shared global data.
Example:
class GlobalData
{
public:
int ticks_;
};
//Other file
class ThatNeedsGlobalData
{
public:
ThatNeedsGlobalData(std::shared_ptr<GlobalData> globalData);
};
This will save you some trouble.
Good luck!
Here are a few things that you need to take care of while trying to use global variables the way you have used.
Ensure that all the header files that the header files that GobalInformation.h includes are also enclosed insides #ifndefs. (I could not see mapinformation.h so I assume you have done it)
Just like CPP, C compiler also does not ensure order of the initialization of variables in different translation units(different C/CPP files).
Hence declare the header file as
//GlobalInformation.h
namespace gi {
extern MapInformation mapInf;
};
In a function that you know would be called first initialize the variable. This way lazy-initialization can also be acheived in C.
I'm writing a header-only logger library and I need global variables to store current logger settings (output flags, log file descriptor etc.). My thoughts:
I can't declare variables as extern, as i don't have access to the translation units to define them
I can't just define global variables in header as it will lead to multiple definitions
static variables in header's functions may seem good at the first glance, but the fact is that every translation unit will have it's own copy of 'global' variable, which is awkward and definitely wrong
I don't also think it is possible to avoid global variables in my case (even though that's what i'd like to do) as i obviously have to store settings somehow between log function calls
Is there any variants i didn't consider yet? Is there any other way to have global variables using headers only.
p.s. I'm looking for both c99/c++11 compatible solution with possible gcc hacks (gcc >= 4.8)
One approach is to hide options behind a function that returns a reference to a local static option. As long as the ODR is not violated (e.g. by some macro-dependent changes of the functions), it is guaranteed that the local static variables are unique across your program. As a simple example, this can be in the header file:
inline bool& someOption()
{
static bool opt = false;
return opt;
}
and in a translation unit:
someOption() = true;
It would probably be useful to group your options into a struct and apply the above technique to an instance to this struct.
Note that this approach is limited to C++ (thanks to #rici for the hint), and might only accidently work out in C using gcc.
Structure your library like follows:
MyLibrary.h:
extern int foo;
extern int bar;
...
#ifdef MY_LIBRARY_IMPL
int foo;
int bar;
...
#endif
Then, in the library documentation, specify that in exactly one translation unit, the user of the library should #define MY_LIBRARY_IMPL before including the header file.
* Question revised (see below) *
I have a cpp file that defines a static global variable e.g.
static Foo bar;
This cpp file is compiled into an executable and a shared library. The executable may load the shared library at run time.
If I am on Linux there seem to be two copies of this variable. I assume one comes from the executable and one from the shared library. Other platforms (HP, Windows) there seems to be only one copy.
What controls this behavior on Linux and can I change it? For example is there a compiler or linker flag that will force the version of this variable from the shared library to be the same as the one from the executable?
* Revision of question *
Thanks for the answers so far. On re-examining the issue it is not actually the problem stated above. The static global variable above does indeed have multiple copies on Windows, so no difference to what I see on Linux.
However, I have another global variable (not static this time) which is declared in a cpp file and as extern in a header file.
On Windows this variable has multiple copies, one in the executable and one in each dll loaded up, and on Linux it only has one. So the question is now about this difference. How can I make Linux have multiple copies?
(The logic of my program meant the value of the static global variable was dependent of the value of the non-static global variable and I started accusing the wrong variable as being the problem)
I strongly suggest you read the following. Afterwards, you will understand everything about shared libraries in Linux. As said by others, the quick answer is that the static keyword will limit the scope of the global variable to the translation unit (and thus, to the executable or shared library). Using the keyword extern in the header, and compiling a cpp containing the same global variable in only one of the modules (exe or dll/so) will make the global variable unique and shared amongst all the modules.
EDIT:
The behaviour on Windows is not the same as on Linux when you use the extern pattern because Windows' method to load dynamic link libraries (dlls) is not the same and is basically incapable of linking global variables dynamically (such that only one exists). If you can use a static loading of the DLL (not using LoadLibrary), then you can use the following:
//In one module which has the actual global variable:
__declspec(dllexport) myClass myGlobalObject;
//In all other modules:
__declspec(dllimport) myClass myGlobalObject;
This will make the myGlobalObject unique and shared amongst all modules that are using the DLL in which the first version of the above is used.
If you want each module to have its own instance of the global variable, then use the static keyword, the behaviour will be the same for Linux or Windows.
If you want one unique instance of the global variable AND require dynamic loading (LoadLibrary or dlopen), you will have to make an initialization function to provide every loaded DLL with a pointer to the global variable (before it is used). You will also have to keep a reference count (you can use a shared_ptr for that) such that you can create a new one when none exist, increment the count otherwise, and be able to delete it when the count goes to zero as DLLs are being unloaded.
The static qualifier applied to a namespace variable means that the scope of the variable is the translation unit. That means that if that variable is defined in a header and you include it from multiple .cpp files you will get a copy for each. If you want a single copy, then mark it as extern (and not static) in the header, define it in a single translation unit and link that in either the executable or the library (but not both).
What compiler did you use on each of these platforms? The behavior you're describing for Linux would be what I'd expect, the static global is only local to that particular file at compile time.
You may be able to work around your issue using the GCC visibility attribute or the visibility pragma
I don't know about HPUX, but on Windows, if you have an exe and a DLL, and they each declare global variables, then there will be two distinct variables. If you are only getting a single variable then one image must be importing the variable from the other.
I have a static library libStatic that defines a global variable like this
Header file libStatic/globals.h:
extern int globvar;
Code file libStatic/globals.cpp:
int globvar = 42;
The DLL libDynamic and the executable runner are using this global variable. Furtheron, libDynamic is linked at run-time into runner (via LoadLibrary(), GetProcAddress(), and the works...)
I understand this will lead to globvar being created twice, once in the heap of runner and once in the heap of libDynamic, which is of course very undesirable.
Is there a good away around this? How can I ensure that libDynamic and runner are using the same globvar?
An easy way would be to let the .DLL point to the global variable of the executable. Right after loading you would call a special function inside that library (something like SetGlobVar(int*)). That way the library will always point to the same global variable as the .EXE.
I am having small problem in making a global variable works. I am using Visual Studio 2008 and standard C++.
I have two projects, one is a static library and second one is a test program which uses this library. I have a global variable in global.h like
#ifndef GLOBAL_H
#define GLOBAL_H
#include <string>
extern std::string globalWord;
#endif // GLOBAL_H!
I have a global.cpp where I am initializing this variable. This variable is used inside my library project. I am setting a value to this variable from the test project, but that value is not getting reflected in the library project.
I have debugged and it shows the new value in test project, but when the control reaches the library project, this variable value shows empty. So is this global variable's scope only limited to the project where it belongs to?
Or is there a better way to do this? I don't want to modify my function or constructor parameters in my library to pass this value.
Any help would be great.
Edit:
Here is how this variable is declared in global.cpp
#include <string>
#include "../global.h"
std::string globalWord = "";
This is how I used it in my library
#include "../global.h"
string text = globalWord;
Thanks
Don't use global variables. Just don't. Much better, if you HAVE to have globally accessible data, is to use a global function which will return globalWord, like this:
std::string globalWord()
{
static std::string word("Hi Mom");
return word;
}
This saves you from initialization order issues (read Effective C++ item #4).
With the "extern" keyword, you're telling the compiler that the actual variable exists somewhere else. You should also create a variable with the same name without the extern, in one and only one place. Ordinarily you'll get an error from the linker if you define two of them, but if one's in the library and one's not it might not figure it out.
Edit: make sure global.cpp is only in the library or test program, not both.
The problem is likely to be one of initialization order. When the program is linked, there are 2 places where globalWord is used in initialization:
in the initialization of text ("string text = globalWord;")
the initialization of globalWord itself
Unfortunately, the C++ standard does not specify the order of initialization of globals that come from different modules. Something similar to Matt's answer of using a function or a simple class (a singleton, for example) to access the global value is the usual way of enforcing a particular initialization order.
The C++ FAQ talks about this a little - if you plan to modify globalWord in your program, the situation is made a little more complex than they discuss because they don't seem to address setting the value hidden behind the "construct on first use" function. Typically something like that would require something like a singleton class.
The kind of behavior you describe seems more like a problem when you have a DLL, but you are saying that your library is static, which looks weird.
Anyway, take care with global variables in multiple libraries, if you have a shared code library (DLL) you'll get a value for each part. Check out this question, can be useful.