why static variables used in EXE and DLL are different?

A

Allen

In a static library, there is a static variable definition.

static CLogger::mapFile;

In both EXE and DLL, I use the same code. CLogReader uses
CLogger::mapFile to do some work.
CLogReader logReader;

But the result is different.

When used in EXE, mapFile constructor is not called? (Why?). See EXE
log below.

Creating map file 0x00499f90 (call CMapFile constructor)
Enter CLogReader now ...
GetMapFile 0x00499f90 ... (return the static mapFile)
Exit CLogReader now ...

When used in DLL, mapFile constructor is called, but after the first
use. See DLL log below

Enter CLogReader ...
GetMapFile 0x10025830 ... (return the static mapFile)
Exit CLogReader ...
Creating map file 0x10025830 (in CMapFile constructor)

It is too strange to understand. Why???
 
G

Gianni Mariani

Allen said:
In a static library, there is a static variable definition. ....
It is too strange to understand. Why???

Do you have a small code sample that exhibits this behaviour ?
 
I

Ian Collins

Allen said:
In a static library, there is a static variable definition.

static CLogger::mapFile;

In both EXE and DLL, I use the same code. CLogReader uses
CLogger::mapFile to do some work.

Off topic here, try a windows programming group.
 
F

F.J.K.

Allen said:
In a static library, there is a static variable definition.

static CLogger::mapFile;

In both EXE and DLL, I use the same code. CLogReader uses
CLogger::mapFile to do some work.
CLogReader logReader;

But the result is different.

When used in EXE, mapFile constructor is not called? (Why?). See EXE
log below.

Creating map file 0x00499f90 (call CMapFile constructor)
Enter CLogReader now ...
GetMapFile 0x00499f90 ... (return the static mapFile)
Exit CLogReader now ...

When used in DLL, mapFile constructor is called, but after the first
use. See DLL log below

Enter CLogReader ...
GetMapFile 0x10025830 ... (return the static mapFile)
Exit CLogReader ...
Creating map file 0x10025830 (in CMapFile constructor)

It is too strange to understand. Why???

Well, the following is a wild guess only, try to follow the guidelines
for posting on this newsgroup for better answers next time, (esp.
http://www.parashift.com/c++-faq-lite/how-to-post.html#faq-5.8)

It seems you have used two static variables of type CLogReader and
CMapFile and rely on the order of their initialization (you probably
want CMapFile initialized before CLogReader). This is a mistake on your
side, as C++ explicitly states, that no guarantee is given, which
constructor will be called first. Out of my head I'd propose one of the
following resolutions.

a) use local variables instead of globals and pass around
references/pointers. The order of initialization for local variables is
guaranteed.
b) use only ONE static object which agglomerates dependent objects,
like

class CLogReaderWithCMapFile {
CMapFile mapFile;
CLogReader logReader;
...
}

Here you have complete control over the order of initialization in
your constructor.

CLogReaderWithCMapfile (...):
mapFile (...),
logReader (...)
{
}

Btw, there's undoubtedly people who are going to tell you this is
off-topic, as it is MS specific. Just ignore them, that's just typical
"background noise" whenever people can tell, you are using MS products
(from the name of your dynamic library, .dll instead of .so). What has
hit you is a classical case of so called "undefined behaviour" in C++,
something totally on topic for this newsgroup ;-)
 
L

Lionel B

Allen said:
In a static library, there is a static variable definition.

static CLogger::mapFile;

In both EXE and DLL, I use the same code. CLogReader uses
CLogger::mapFile to do some work.
CLogReader logReader;

But the result is different.

[snip]

Btw, there's undoubtedly people who are going to tell you this is
off-topic, as it is MS specific.

How do we know it *isn't* MS specific since insufficient code was posted?
You yourself admit to making a "wild guess" (albeit quite likely a correct
one).
Just ignore them, that's just typical "background noise" whenever people
can tell, you are using MS products (from the name of your
dynamic library, .dll instead of .so).

Nonsense. You may well get (justifiable) complaints if your question is
evidently MS-specific, or Linux-specific, or
whatever non-C++-language-specific. If your query is on-topic nobody cares
what products you're using.
What has hit you is a classical case of so called "undefined behaviour"
in C++, something totally on topic for this newsgroup ;-)

....or maybe it's something MS-specific ;-)
 
A

Allen

Well, the following is a wild guess only, try to follow the guidelines
for posting on this newsgroup for better answers next time, (esp.
http://www.parashift.com/c++-faq-lite/how-to-post.html#faq-5.8)

It seems you have used two static variables of type CLogReader and
CMapFile and rely on the order of their initialization (you probably
want CMapFile initialized before CLogReader). This is a mistake on your
side, as C++ explicitly states, that no guarantee is given, which
constructor will be called first. Out of my head I'd propose one of the
following resolutions.

a) use local variables instead of globals and pass around
references/pointers. The order of initialization for local variables is
guaranteed.
b) use only ONE static object which agglomerates dependent objects,
like

class CLogReaderWithCMapFile {
CMapFile mapFile;
CLogReader logReader;
...
}

Here you have complete control over the order of initialization in
your constructor.

CLogReaderWithCMapfile (...):
mapFile (...),
logReader (...)
{
}


Yes. You are right. I cannot be sure that it is the right answer. But
it works. Thank you!
After I post this topic, I kept testing on this question. Now I find
out a solution.

In the .dll implementation, as you said, I used a global variable
CLogReader. It is the point. Now I changed it to be a local static
variable and a global pointer to solve the problem Below is the sample
codes.

/// previous version
CLogReader logReader;

DLL_EXPORT void InitLogReader()
{
logReader.InitLogReader();
}

DLL_EXPORT void ReadMesg()
{
logReader.ReadMesg();
}

/// corrected version
CLogReader* pLogReader = NULL;

DLL_EXPORT void InitLogReader()
{
static CLogReader logReader;
logReader.InitLogReader();

pLogReader = &logReader;
}

DLL_EXPORT void ReadMesg()
{
if (pLogReader == NULL)
{
printf("\nLogReader is not initialized");
return;
}
pLogReader->ReadMesg();
}

I think it is not easy to give the anwser to this question. Thank you
again.
 
M

Madkour

Hi Allen,
I think the reason for this strange behaviour is caused by the way the
OS handles dlls and exes.
dll's are better for performance since they are initialized and
instantiated once (during their first call) and continue to operate to
serve all client programmes. Only one copy of the dll is running at any
one time. Exe's however, are treated just as any other programme is. A
fresh copy is instantiated in a separate memory space every time it's
required. This obviously has performance overhead.

So, if the constructor is called only the very first time the programme
is run, it will only run once in the case of a dll (that is when the
dll is called for the first time) and will be called every time the exe
is called (since a fresh copy of the exe will be created every time
it's needed).

In all fairness, I think this is more of a windows programming issue!
:eek:)

Cheers,
Madkour
 
F

F.J.K.

Lionel said:
How do we know it *isn't* MS specific since insufficient code was posted?
You yourself admit to making a "wild guess" (albeit quite likely a correct
one).

Well, there wasn't enough code posted to be sure either way. However,
some guesses are "wilder" than others ;-) The OP was relying on order
of initializations. Order of constructor calls for global objects is a
pretty common pitfall of the language.
...or maybe it's something MS-specific ;-)

To be honest, there probably will be some kind of "MS-specificity" to
the problem. Linking is notoriously underdefined by language
standards, you've got no chance to keep this area free of platform
specific information. But that's a problem of C++, too.
 
L

Lionel B

Well, there wasn't enough code posted to be sure either way. However,
some guesses are "wilder" than others ;-) The OP was relying on order
of initializations. Order of constructor calls for global objects is a
pretty common pitfall of the language.


To be honest, there probably will be some kind of "MS-specificity" to
the problem. Linking is notoriously underdefined by language standards,
you've got no chance to keep this area free of platform specific
information. But that's a problem of C++, too.

As it turns out, the OP's problem had nothing to do with linking or
MS-specificity, but - as you correctly guessed - with the well-known
"gotcha" of global object initialisation order.

The point I was trying to make is that had the OP posted code we might have
spotted this straight off - and nobody would have had valid cause to
complain about MS-specificity since it would have been clear that this was
not the issue... this despite the fact that the OP himself seemed to think
it /was/ an MS-specific (or possibly linkage) thing and therefore
shouldn't have posted here! You might say he accidentally posted to the
correct forum through ignorance... :)
 
F

F.J.K.

Lionel said:
not the issue... this despite the fact that the OP himself seemed to think
it /was/ an MS-specific (or possibly linkage) thing and therefore
shouldn't have posted here! You might say he accidentally posted to the
correct forum through ignorance... :)

sometimes, ignorance is bliss ;-)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,048
Latest member
verona

Latest Threads

Top