How do static variables inside functions work?

Up vote 11 down vote favorite share g+ share fb share tw.

In the following code: int count(){ static int n(5); n = n + 1; return n; } the variable n is instantiated only once at the first call to the function. There should be a flag or something so it initialize the variable only once.. I tried to look on the generated assembly code from gcc, but didn't have any clue. How does the compiler handle this?

C++ c compiler static link|improve this question edited Oct 12 '11 at 13:26jpalecek20.1k2348 asked Oct 12 '11 at 13:23Yousf1,276217 94% accept rate.

1 Try with a type that has a non-trivial constructor. You should see more traces of what is actually done. (See e.g. Stackoverflow.com/questions/6967179/… for what type of stuff can happen around this type of static initializer with GCC) – Mat Oct 12 '11 at 13:32 @Mat: non-trivial and non-constexpr, one might add.

E.g. Std::shared_ptr() is OK. – Kerrek SB Oct 12 '11 at 13:38.

This is, of course, compiler-specific. The reason you didn't see any checks in the generated assembly is that, since n is an int variable, g++ simply treats it as a global variable pre-initialized to 5. Let's see what happens if we do the same with a std::string: #include void count() { static std::string str; str += ' '; } The generated assembly goes like this: _Z5countv: .

LFB544: . Cfi_startproc . Cfi_personality 0x3,__gxx_personality_v0 .

Cfi_lsda 0x3,. LLSDA544 pushq %rbp . Cfi_def_cfa_offset 16 movq %rsp, %rbp .

Cfi_offset 6, -16 . Cfi_def_cfa_register 6 pushq %r13 pushq %r12 pushq %rbx subq $8, %rsp movl $_ZGVZ5countvE3str, %eax movzbl (%rax), %eax testb %al, %al jne . L2 ; Cfi_offset 3, -40 .

Cfi_offset 12, -32 . Cfi_offset 13, -24 movl $_ZGVZ5countvE3str, %edi call __cxa_guard_acquire ; acquire the lock testl %eax, %eax setne %al testb %al, %al je . L2 ; check again movl $0, %ebx movl $_ZZ5countvE3str, %edi .

LEHB0: call _ZNSsC1Ev ; call the constructor . LEHE0: movl $_ZGVZ5countvE3str, %edi call __cxa_guard_release ; release the lock movl $_ZNSsD1Ev, %eax movl $__dso_handle, %edx movl $_ZZ5countvE3str, %esi movq %rax, %rdi call __cxa_atexit ; schedule the destructor to be called at exit jmp . L2 .

L7: . L3: movl %edx, %r12d movq %rax, %r13 testb %bl, %bl jne . L5 .

L4: movl $_ZGVZ5countvE3str, %edi call __cxa_guard_abort . L5: movq %r13, %rax movslq %r12d,%rdx movq %rax, %rdi . LEHB1: call _Unwind_Resume .

L2: movl $32, %esi movl $_ZZ5countvE3str, %edi call _ZNSspLEc . LEHE1: addq $8, %rsp popq %rbx popq %r12 popq %r13 leave ret . Cfi_endproc The line I've marked with the bypass initialization comment is the conditional jump instruction that skips the construction if the variable already points to a valid object.

Good point - if the variable is initialized to a constant expression, then you probably don't need any flag at all. – Kerrek SB Oct 12 '11 at 13:35 1 +1 Great answer – Chris A. Oct 12 '11 at 14:30.

This is entirely up to the implementation; the language standard says nothing about that. In practice, the compiler will usually include a hidden flag variable somewhere that indicates whether the static variable has already been instantiated or not. The static variable and the flag will probably be in the static storage area of the program (e.g. The data segment, not the stack segment), not in the function scope memory, so you may have to look around about in the assembly.

(The variable can't go on the call stack, for obvious reasons, so it's really like a global variable. "static allocation" really covers all sorts of static variables! ) Update: As @aix points out, if the static variable is initialized to a constant expression, you may not even need a flag, because the initialization can be performed at load time rather than at the first function call.

In C++11 you should be able to take advantage of that better than in C++03 thanks to the wider availability of constant expressions.

1 I have never heard of these secret "hidden flags". Which compiler does this, can you give any sources? At least every compiler/linker I have seen simply initializes all statics at program startup, then threat them as they would with any global variable.

EDIT: Ah nevermind, didn't see the C++ tag. You should probably clearify that this "flag" only applies to class constructors, not primitive data types like int. – Lundin Oct 12 '11 at 13:44 3 @Lundin: What about void foo() { static int n = read_from_user(); }?

How can this be initialized at load time? – Kerrek SB Oct 12 '11 at 13:48 I am pretty sure it also applies to C if you initialize to e.g. The result of a function static int foo = get_initial_foo(); – Random832 Oct 12 '11 at 13:50 2 @Random: In C, initializer elements must be constant. – Luther Blissett Oct 12 '11 at 14:05 Well, actually the standard is pretty specific about how these things should behave, including the order in which non-trivial constructors and destructors should be run.

– ninjalj Oct 12 '11 at 15:23.

It's quite likely that this variable will be handled just as ordinary global variable by gcc. That means the initialization will be statically initialized directly in the binary. This is possible, since you initialize it by a constant.

If you initialized it eg. With another function return value, the compiler would add a flag and skip the initialization based on the flag.

Function static variables are initialised on the first call, not at startup. – R. Martinho Fernandes Oct 12 '11 at 13:29 @R.

MartinhoFernandes The as-if rule applies and all compilers will put the value 5 into the binary and not execute any code on first call. – David Heffernan Oct 12 '11 at 13:31 @DavidHeffernan oh, I didn't pay much attention to the example. You're right.

– R. Martinho Fernandes Oct 12 '11 at 13:32 Yes, this is exactly how it will be done. All statics no matter where they are declared, as well as all globals, will be placed in a special RAM segment which is initialized at program start.

When the code with the "local" static is executed, it is treated just as if the static was declared outside the function and already initialized. – Lundin Oct 12 '11 at 13:40 2 It should be noted that while C++ supports static local variables initialised by a non-constant expression, C seems to not allow that, at least gcc says error: initializer element is not constant when you say static int x = rand(). – Blagovest Buyukliev Oct 12 '11 at 13:49.

I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.

Related Questions