Okay to declare static global variable in .h file?

2019-01-22 00:04发布

问题:

static keyword keeps the scope of a global variable limited to that translation unit. If I use static int x in a .h file and include that .h file every other file, won't they all belong to the same translation unit? Then, won't x be visible everywhere? So what is the role of static now?

Also, is there any use of static const int x ,where x is a global variable? Aren't all const global variables static by default? And is a const variable's scope limited to the TU even if it confined in a for loop in the file?

回答1:

If you write

static const int x

in an .h file then every translation unit that #include-s this .h will have its own private variable x.

If you want to have 1 global variable visible to everyone you should write

extern const int x;

in the .h file and

const int x = ...;

in one of the .cpp files.

If you want to have a static const int visible to just one translation unit - don't mention it in the .h files at all.



回答2:

If I use static int x in a .h file and include that .h file every other file, won't they all belong to the same translation unit?

If you declare something as static (not inside a class, for class static keyword has a different semantic), that static variable cannot be seen outside its TU. So putting it in the header file will cause each TU including that header to have a different private copy of that static variable.

And is a const variable's scope limited to the TU even if it confined in a for loop in the file?

NO. Even for a static const value, the scope is determined by it's declaration. So the scope will be limited by your for brackets.



回答3:

you will end up will private copies of that variable per translation, which will result in bloat if you put it there. it would also make no sense to have to random copies all over the place. no it's not ok.

you can declare a const int in a namespace block; that's ok.



回答4:

The observable difference for variables that are const qualified is that in the static version you will get one copy per translation unit and so address comparisons of two such copies may fail.

If you never use the address of your const variable any modern compiler should be able to just use the value and optimize the variable itself out. In such a case a static const-qualified variable is completely fine.



回答5:

Basically, each source file together with all included header files is a single translation unit. So If you have a static variable in a header file then it will be unique in each source file (translation unit) the header file is included in.



回答6:

"static global" doesn't make sense, they are in a way each other's opposites.

The term "global" is often misused to describe a variable declared outside any function at file scope. But rather, a global variable is one with external linkage, that can be accessed by any file in the project - hence global.

The opposite of external linkage is internal linkage, which means that a variable can only get accessed by the translation unit where it is declared. Translation unit meaning one .c file and all the headers included by it (recursively).

static is a guarantee that a variable gets internal linkage. Thus other translation will not be able to access it or declare extern variables referring to it.

What happens if you declare a static variable in a header file is that more than one translation unit will get a separate variable with that name. The code will compile fine, although clever linkers will notice this and give a linker error. These kind of linker errors are often non-descriptive and hard to track down.

This leads us to the following best practices:

  • Never declare any variables inside a header file, as this often creates subtle bugs and linker errors.
  • To prevent such bugs, always surround all header files with "header guards":

    #ifndef MYHEADER_H 
    #define MYHEADER_H 
      /* contents of header */ 
    #endif
    
  • All variables declared at file scope should be declared static, for the purpose of private encapsulation and to reduce namespace clutter. Similarly, extern should be avoided, as it leads to bad design and spaghetti programming.