gagou7
gagou7

Reputation: 313

Access external struct attribute from outside function

I was playing a bit with external variables and was wondering why I cannot access an external structure from outside functions?

Here's my code:

a.h

struct testing {

   unsigned int val;
   const char* str;

   testing(unsigned int aVal, const char* aStr) : val(aVal), str(aStr){};
}

extern testing externalStruct;

a.c

#include "a.h"

testing externalStruct(10, "test");

test.c

#include <iostream>
#include "a.h"

unsigned int valCopy = externalStruct.val;
const char* strCopy = externalStruct.str;

int main()
{
   std::cout<<"Direct val : "<<externalStruct.val<<std::endl; // Working, print 10
   std::cout<<"Direct str : "<<externalStruct.str<<std::endl; // Working, print "test"
   std::cout<<"Copy val : "<<valCopy<<std::endl; // Print 0 instead of 10
   std::cout<<"Copy str : "<<strCopy<<std::endl; // Print nothing

   return 0;
}

Any idea?

Upvotes: 2

Views: 256

Answers (3)

Alex Lop.
Alex Lop.

Reputation: 6875

The order of initialization of the global objects is not defined.

In this case I guess that valCopy and strCopy were initialized before the constructor of externalStruct was invoked (=> initialized with junk).

If you put the initialization of valCopy and strCopy into the main body I believe everything will work properly:

int main()
{

   unsigned int valCopy = externalStruct.val;
   const char* strCopy = externalStruct.str;

   std::cout<<"Direct val : "<<externalStruct.val<<std::endl; // Working, print 10
   std::cout<<"Direct str : "<<externalStruct.str<<std::endl; // Working, print "test"
   std::cout<<"Copy val : "<<valCopy<<std::endl; // ??? did it work?
   std::cout<<"Copy str : "<<strCopy<<std::endl; // ??? did it work?

   return 0;
}

EDIT

More info is here "C++ global initialization order ignores dependencies?"

Upvotes: 0

tofro
tofro

Reputation: 6063

You are being tricked by the static initialization order fiasco - One of the shortcomings of C++.

Both

unsigned int valCopy = externalStruct.val;
const char* strCopy = externalStruct.str;

and

testing externalStruct(10, "test");

are (and need to be) actually called before main() is executed. Unfortunately, C++ has no language construct that allows you to express in what order the initialization should be done - this is more ore less randomly decided by the compiler - In your case, the first block is apparently executed before the second, leading to the fact that externalStruct has not been initialized yet when you copy values from there into valCopy and strCopy.

You can work around this language deficiency by wrapping the initializations into functions that return a statically initialized value - This gives you control over the order those initializations are done.

a.c:

testing &x() {
   static testing *t = new testing(10, "test");
   return *t;
}

test.c

...
valCopy = x().val;
strCopy = x().str;
... 

Upvotes: 1

marcinj
marcinj

Reputation: 49986

This problem is caused by the fact that order of initialization of static (global) variables is unknown. It even has a name static initialization order fiasco. This means that global variables from test.c translation unit were initialized before global variables from a.c transation unit.

The usual solution is to use function with static variable. When function is called then static variable (during first use) is initialized. With c++11 initialization of such static function local variables is thread safe.

Solution for your code could look as follows:

a.h

//...

testing& GetExternalStruct();

a.c

//...

testing& GetExternalStruct() {
   static testing externalStruct(10, "test");
   return externalStruct;
}

test.c

unsigned int valCopy = GetExternalStruct().val;
const char* strCopy = GetExternalStruct().str;

Upvotes: 2

Related Questions