The difference between a static variable in a free function and a static member function

I have a code like this:

struct Storage { static int GetData() { static int global_value; return global_value++; } }; int free_func() { static int local_value; return local_value++; } int storage_test_func() { return Storage::GetData(); } 

Compilation on OSX:

 $ clang++ 1.cpp -shared 

And nm works:

 $ nm | c++filt 

I get strange results:

 0000000000000f50 T storage_test_func() 0000000000000f30 T free_func() 0000000000000f60 unsigned short Storage::GetData() 0000000000001024 bool free_func()::local_value 0000000000001020 D Storage::GetData()::global_value U dyld_stub_binder 

Two characters ( local_value and global_value ) have a different relationship! One visible difference is that global_value is defined in a static member function, and local_value is defined in a free function.

Can someone explain why this is happening?

UPD:

After reading the comments, it seems like I should clarify the situation. Maybe using c++filt was a bad idea. Without this, it shows:

 $ nm 0000000000000f50 T __Z17storage_test_funcv 0000000000000f30 T __Z9free_funcv 0000000000000f60 t __ZN7Storage7GetDataEv 0000000000001024 b __ZZ9free_funcvE11local_value 0000000000001020 D __ZZN7Storage7GetDataEvE5value U dyld_stub_binder 

So yes. __ZZ9free_funcvE11local_value goes to BSS, and __ZZN7Storage7GetDataEvE5value goes to the data section.

man nm says that:

If the character is local (not external), the character type is instead represented by the corresponding lowercase letter.

And this is what I see. __ZZ9free_funcvE11local_value marked with lowercase b , and __ZZN7Storage7GetDataEvE5value capital D

And this is the main part of the question. Why it happens?

UPD2 Another way:

 $ clang++ -c -emit-llvm 1.cpp $ llvm-dis 1.bc 

shows how these variables are represented internally:

 @_ZZ9free_funcvE11local_value = internal global i32 0, align 4 @_ZZN7Storage7GetDataEvE5value = global i32 0, align 4 

UPD3

There were also some issues related to section symbols. Putting __ZZ9free_funcvE11local_value into a text section does not change its visibility:

 struct Storage { static int GetData() { static int value; return value++; } }; int free_func() { static int local_value = 123; return local_value++; } int storage_test_func() { return Storage::GetData(); } 

Compilation:

 $ clang++ 1.cpp -shared 

Verification:

 $ nm 

gives:

 0000000000000f50 T __Z17storage_test_funcv 0000000000000f30 T __Z9free_funcv 0000000000000f60 t __ZN7Storage7GetDataEv 0000000000001020 d __ZZ9free_funcvE11local_value 0000000000001024 D __ZZN7Storage7GetDataEvE5value 

Now both characters are in the data section, but another one is local and the other global . And the question is why is this happening? Can anyone have logic to solve such a compiler?

+7
c ++ static-methods linkage
source share
2 answers

There is no difference in a local static variable in a static member function and a local static variable in a free function.

Two characters (local_value and global_value) have a different relationship!

In the standard nomenclature and from the point of view of the standard, both variables have no connection.

The corresponding difference between functions is not that one of them is a static member function and the other is not. The corresponding difference is that the former is a built-in function, but the latter is not.

Non-built-in functions can only be defined in one translation unit, so their local static variables should not be available from other translation units.

On the other hand, inline functions must be defined in each translation unit that uses them. And since a local static object must reference the same object globally, this object must be visible to several translation units.

+5
source share

Values ​​will be linked in different storage partitions.

000000000001020 D Storage :: GetData () :: global_value

D indicates that your variable will be associated with the section to be initialized. On the nm man page:

  "D" "d" The symbol is in the initialized data section. 

local_value will not be initialized with c-startup code.

After linking, I got:

0804a0d0 b free_func () :: local_value

0804a0d8 u Storage :: GetData () :: global_value

Also from nm man page:

  "B" "b" The symbol is in the uninitialized data section (known as BSS). "U" The symbol is undefined. "u" The symbol is a unique global symbol. This is a GNU extension to the standard set of ELF symbol bindings. For such a symbol the dynamic linker will make sure that in the entire process there is just one symbol with this name and type in use. 

The reason is that the values ​​will be initialized using standard startup initialization (data section) or not (bss section). Section names are usually not specified, but are used in common implementations.

You can find a lot of Q&A up to "When and where will var be initialized or not." eg .: When are static and global variables initialized?

Clarification: (I hope)

Just because a variable is not initialized with a start code does not mean that it is not initialized. A static variable inside a method / function is usually initialized the first time it contains a code block. If you want to know how your compiler does this work, look at the assembly.

For gcc, you will find the __cxa_ labels around the value initialization, which protects your vars from multiple init.

+1
source share

All Articles