Static function-vars and the compiler

M

Marijn

I'd like to know how compilers usually handle static variables that
are declared inside a function (as opposed to static class-members).
Like in:

int counter(){
static int c=0;
++c;
return c;
}

I would assume the compiler changes it into something like this:

bool counter_c_is_initialized = false;
int counter_c;
int counter(){
if (!counter_c_is_initialized){
c = 0;
counter_c_is_initialized = true;
}
++c;
return c;
}

Since they do not seem to be initialized when the function is never
called. Am i correct here? So if this is correct there will be an
extra conditional every time the function is called.

I've lately taken to implementing singletons with a static function
var, something like this:

class Singleton{
public:
static Singleton& get(){
static Singleton single;
return single;
}
private:
Singleton(){}
};

This only works if the constructor does not take arguments, but it
does take care of the destruction of the object when the program
terminates. Any problems with this form of singleons? I guess i do not
have precise control over the order in which such objects get
destructed, so if the destructor depends on another semi-global object
it could cause problems.

Marijn Haverbeke
 
P

Peter van Merkerk

Marijn said:
I'd like to know how compilers usually handle static variables that
are declared inside a function (as opposed to static class-members).
Like in:

int counter(){
static int c=0;
++c;
return c;
}

I would assume the compiler changes it into something like this:

bool counter_c_is_initialized = false;
int counter_c;
int counter(){
if (!counter_c_is_initialized){
c = 0;
counter_c_is_initialized = true;
}
++c;
return c;
}

Since they do not seem to be initialized when the function is never
called. Am i correct here?

Some time ago I digged into the assembly output of the Borland C++
Builder compiler. This compiler deals with static objects declared
inside a function exactly the way you described. Unfortunately this
solution is not multi-thread safe. I didn't check this with other
compilers, and the standard dictates only that static objects are only
initialized once, not how compilers should solve this problem. I.e. your
mileage may vary.
So if this is correct there will be an
extra conditional every time the function is called.

It is plausible that something like that will take place, though in
theory the compiler may resort to self modifying code as well.
I've lately taken to implementing singletons with a static function
var, something like this:

class Singleton{
public:
static Singleton& get(){
static Singleton single;
return single;
}
private:
Singleton(){}
};

This only works if the constructor does not take arguments, but it
does take care of the destruction of the object when the program
terminates. Any problems with this form of singleons? I guess i do not
have precise control over the order in which such objects get
destructed, so if the destructor depends on another semi-global object
it could cause problems.

You are correct; only the order of destruction within a translation unit
(.cpp file) is guaranteed. The book "Modern C++ Design" from Andrei
Alexandrescu does discusses techniques to deal with this problem.
 
M

Marijn

It is plausible that something like that will take place, though in
theory the compiler may resort to self modifying code as well.

Self-modifying code? Wow, sounds weird. Do any compilers actually do
that? That would make this static-variable-initialization much more
efficient though. I'll try to decipher the assembly that G++ spits
out. (My assembly reading skills are quite lousy.)

Marijn
 
P

Peter van Merkerk

Marijn said:
Self-modifying code? Wow, sounds weird. Do any compilers actually do
that?

Not any that I know of. And I don't think many will since self-modifying
code is in most cases a bad idea. I just mentioned it to make it clear that
compilers do not have to follow the method you described. But I expect many
compilers do the check with an additional helper variable for static objects
with non-trivial constructors.

Note that for primitive types like 'int' the compiler may also (and probably
will) use initialized memory, which is set to the initial value of the
static variable. That way no initialization check is needed when the
function is entered.
That would make this static-variable-initialization much more
efficient though.

static variable initialization is usually not a real performance concern.
I'll try to decipher the assembly that G++ spits
out. (My assembly reading skills are quite lousy.)

That can be an interesting excercise. Combined with common sense it can
provide you with valuable insights about the optimization capabilities of
the compiler. One of the most important lessons to be learned is probably
that many of those "clever" & dirty optimization tricks some people are
eager to use have little or no effect on the efficiency. Some of them are
even detrimental. An excellent example is the "integer divide by 7 trick?"
thread of a week ago. Any halfway decent compiler will generate the optimal
code sequence to do i/7 for a given platform. Anyone who has ever studied
the assembly output of a contemporary compiler in recent years knows that,
and wouldn't bother to figure how to do it with shifts and subtractions.

Just don't get too carried away with the assembly stuff and keep in mind
that different compilers use different solutions.
 
J

Jack Klein

I'd like to know how compilers usually handle static variables that
are declared inside a function (as opposed to static class-members).
Like in:

int counter(){
static int c=0;
++c;
return c;
}

I would assume the compiler changes it into something like this:

bool counter_c_is_initialized = false;
int counter_c;
int counter(){
if (!counter_c_is_initialized){
c = 0;
counter_c_is_initialized = true;
}
++c;
return c;
}

I would certainly hope not, at least not on "regular" desk top
platforms. Generally the initial values for static POD data is in the
executable image file, and it written into the proper place in memory
by the OS program loader at the same time as it writes the executable
binary image into a different part of memory.
Since they do not seem to be initialized when the function is never
called. Am i correct here? So if this is correct there will be an
extra conditional every time the function is called.

Since there is no possible way in a conforming C++ program to find out
the value of that static object without calling the function, it makes
no difference whether it is initialized or not. But why do you think
it is not?
I've lately taken to implementing singletons with a static function
var, something like this:

class Singleton{
public:
static Singleton& get(){
static Singleton single;
return single;
}
private:
Singleton(){}
};

This only works if the constructor does not take arguments, but it
does take care of the destruction of the object when the program
terminates. Any problems with this form of singleons? I guess i do not
have precise control over the order in which such objects get
destructed, so if the destructor depends on another semi-global object
it could cause problems.

Marijn Haverbeke

When you are talking about non-POD objects with constructors, there is
no requirement nor guarantee that they be initialized at load-time.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++ ftp://snurse-l.org/pub/acllc-c++/faq
 
M

Marijn

Jack Klein said:
Since there is no possible way in a conforming C++ program to find out
the value of that static object without calling the function, it makes
no difference whether it is initialized or not. But why do you think
it is not?

Actually, the variable might be a user-defined class, whose
constructor has side effects. I have a logfile class singleton
initialized as a function static as i described in my first post, and
when it initializes it opens a file and writes something to it. When
my program does not log anything, the logfile is not created, so that
would prove the variable is only initialized when the function is
actually called. Other compilers might do this differently though, i'd
have to check.

Marijn
 

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,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top