Access global static member

Please have a look at my code. I don't know where/how to initialize "myGlobal" such that I can change its value from my unit test.

mylibrary.dll
-------------------------------------------

//mylibrary.h

class A
{
...
static int myGlobal;

static void ResetGlobal();
}

inline
A::ResetGlobal() { A::myGlobal = 0; }


//mylibrary.cpp

A::myGlobal = 0;

... //increment myGlobal



myunittest.exe
-------------------------------------------

//myunittest.cpp

#include mylibrary.h

//A::myGlobal = 0; // if I uncomment this it compiles but myGlobal doesn't reflect changes "made in mylibary.cpp"...

...
TEST
{
A::ResetGlobal();
}

--> error error LNK2001: unresolved external symbol A::myGlobal
sometimes, at least for me, a compiler will say the variable wasnt initailized when it has been. may it is just a formatting issue
hmm..

From a myunittest.exe point of view the variable doesn't seem to be initialized. This is probably because I only include mylibrary.h but the initialization is actually done in mylibrary.cpp...

any other hints? thank you!
You need to uncomment that line. What do you mean it 'doesn't reflect changes'?
he means that the code executed before the line that "doesn't reflect changes" would undermind the changes made by the code before that line. that is/was there to see if it compiles when A is initialized at that point in the program...
Yes, if I uncomment this line everything compiles fine. However, I set A::myGlobal in mylibrary.cpp to 100. I now would like to reset this value in my unit test to 0. This seems not possible...

myGlobal in myunittest doesn't seem to be the same as myGlobal in mylibrary.cpp.

(because I initialized A::myGlobal twice; once in mylibrary.cpp and one in myunittest.cpp???)

I'm confused here. I thought a static member exists once. I therefore would like to initialize it once and then access and change it from mylibrary.cpp AND myunittest.cpp...
please let me know if you want me to provide any other info/code/...
oh! i think I see the problem...

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
mylibrary.dll

//mylibrary.h

class A
{
...
static int myGlobal;

static void ResetGlobal();
}

inline
A::ResetGlobal() { A::myGlobal = 0; }


//mylibrary.cpp

A::myGlobal = 0;

... //increment myGlobal



myunittest.exe
-------------------------------------------

//myunittest.cpp

#include mylibrary.h

//A::myGlobal = 0; // if I uncomment this it compiles but myGlobal doesn't reflect changes "made in mylibary.cpp"...

...
TEST
{
A::ResetGlobal();
}


where you have A::MyGlobal = 0; you are using MyGlobal as a function inside a class... I am pretty sure you must use it like a member... aka A.MyGlobal = 0; same with other spots you have A::MyGlobal it might need to be A.MyGlobal... try this instead...

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
mylibrary.dll

//mylibrary.h

class A
{
...
static int myGlobal;

static void ResetGlobal();
}

inline
A::ResetGlobal() { A.myGlobal = 0; }


//mylibrary.cpp

A.myGlobal = 0;

... //increment myGlobal



myunittest.exe
-------------------------------------------

//myunittest.cpp

#include mylibrary.h

//A.myGlobal = 0; // if I uncomment this it compiles but myGlobal doesn't reflect changes "made in mylibary.cpp"...

...
TEST
{
A::ResetGlobal();
}


I am transferring from c# though so it could just be a c# thing... but either way give it a shot for me : )
Last edited on
This is incorrect:
A::myGlobal = 0;
You should specify the type of the variable:
int A::myGlobal = 0;
@Watachiaieto: A.MyGlobal doesn't compile...

@Xander314: Oops, I've done this in my code but it got lost while copying it to the post... I apologize.

Therefore I'm still in the dark... :-(
A.MyGlobal is C# notation. In C++ it should be A::MyGlobal for a static variable (:: is the scope resolution operator).

You've also missed out the void keyword on your A::ResetGlobal() function, though I assume that is another errors which arose while transferring the code to the forum.

I think I have the problem. You only need to define and initialize the variable in one source code file. The others need only have access to a declaration (so the compiler knows about the variable), which in this case is inside the class definition.

When you define and initialize the variable in both source code files, I am guessing it results in the creation of two different variables (this may be wrong...).

In your original post, were you saying that you got an unresolved external symbol linker error when you only defined the variable in one source code file? If so, then are you definitely compiling the two source files together (or else linking the one to the other).
You've also missed out the void keyword on your A::ResetGlobal() function, though I assume that is another errors which arose while transferring the code to the forum.


Yes, I forgot that as well.

When you define and initialize the variable in both source code files, I am guessing it results in the creation of two different variables (this may be wrong...).


I thought so too. Therefore I commented the initialization out in the unit test.

In your original post, were you saying that you got an unresolved external symbol linker error when you only defined the variable in one source code file?


Yes.

If so, then are you definitely compiling the two source files together (or else linking the one to the other).


That's probably the point. To be honest, I don't know (but doesn't seem to be...). I compiled my library as a dll. It seems like my library.cpp is still unknown to the unit-test. How can I change that? I was told including a cpp-file is supposed to be very bad style...
Yes, you definitely shouldn't #include cpp files. If you compile the two cpp files together in a project (no need to include them in one another), then that is sufficient.

If you have already compiled on as a DLL then you'll either have to load the DLL into memory yourself and then get the address of the variable in it (I can probably help you with this, but it's a bit of a pain, really). Or, you could rebuild the DLL file and find the option to create an import library. This will be a file you link to your project like a static library, but in fact it just gives you access to the DLL. Then you put the DLL in the same directory as the other binary and voila!

If you are using Visual Studio or Code::Blocks, I can probably tell you how to create an import library.
Last edited on
We're getting closer...

Or, you could rebuild the DLL file and find the option to create an import library.


Let's try that.

I'm using Visual Studio. It seems like a mylibrary.dll and mylibrary.lib is created (and I do link to mylibrary.lib from myunittest). However, myunittest doesn't figure out that myGlobal is already initialized. Do I have to mark myGlobal specially (e.g. extern ...)?

Thank you for helping me.
Okay. I've got it - with the help of Microsoft's sample project. You might want to use it yourself actually, if only for a learning experience. Make a new Win32 project and set the type to DLL, and also check "Export Symbols". Then it will create some starting files which illustrate exactly what you have to do.

Basically, in your DLL project, you must declare all free functions and variables, as well as classes to be intended for export from a DLL, by prefacing their names with __declspec(dllexport).

Then, in the project using the DLL, you must declare these symbols as intended to be imported from a DLL, by prefacing their names with __declspec(dllimport).

On the face of it, this means that you can't use the same header file for the DLL project and the DLL user project. However, Microsoft suggest a cunning solution. Instead of writing the declspec out each time, use something like the following:
1
2
3
4
5
#ifdef EXPORT
#define DLLAPI __declspec(dllexport)
#else
#define DLLAPI __declspec(dllimport)
#endif 


Then just put DLLAPI before the names of the symbols to be exported, rather than writing the __declspec yourself. Then, in the DLL project, in the compiler options, define the preprocessor macro EXPORT so that the symbols are marked for export from a DLL. Then in the target project, this macro won't be defined so they'll be marked for input!

Note: __declspec(dllimport), etc might be specific to Visual C++. Okay in MinGW it looks like you can do the same as for Visual C++. On Linux, none of it is necessary apparently, but I haven't actually tried that...
Last edited on
Yes, that was it...

However, export on static members doesn't seem to work. Therefore I had to make a workaround (which is even better, I guess):

Instead of exposing my static member variable, I encapsulate it in a static member function which in turn is defined in mylibrary.cpp and exposed according to your explanation.

OK, thanks again. You made my day!!

Have a good one too!
There's no need to do that. What you should do is mark the class as a whole for export/import (with DLL_API or whatever). Then it's members should be accessible. I tried it and eventually got it to work.
Topic archived. No new replies allowed.