Variable declarations in header files - static or not?
When refactoring away some #defines
I came across declarations similar to the following in a C++ header file:
static const unsigned int VAL = 42;
const unsigned int ANOTHER_VAL = 37;
The question is, what difference, if any, will the static make? Note that multiple inclusion of the headers isn't possible due to the classic #ifndef HEADER
#define HEADER
#endif
trick (if that matters).
Does the static mean only one copy of VAL
is created, in case the header is included by more than one source file?
Solution 1:
The static
and extern
tags on file-scoped variables determine whether they are accessible in other translation units (i.e. other .c
or .cpp
files).
static
gives the variable internal linkage, hiding it from other translation units. However, variables with internal linkage can be defined in multiple translation units.extern
gives the variable external linkage, making it visible to other translation units. Typically this means that the variable must only be defined in one translation unit.
The default (when you don't specify static
or extern
) is one of those areas in which C and C++ differ.
In C, file-scoped variables are
extern
(external linkage) by default. If you're using C,VAL
isstatic
andANOTHER_VAL
isextern
.In C++, file-scoped variables are
static
(internal linkage) by default if they areconst
, andextern
by default if they are not. If you're using C++, bothVAL
andANOTHER_VAL
arestatic
.
From a draft of the C specification:
6.2.2 Linkages of identifiers ... -5- If the declaration of an identifier for a function has no storage-class specifier, its linkage is determined exactly as if it were declared with the storage-class specifier extern. If the declaration of an identifier for an object has file scope and no storage-class specifier, its linkage is external.
From a draft of the C++ specification:
7.1.1 - Storage class specifiers [dcl.stc] ... -6- A name declared in a namespace scope without a storage-class-specifier has external linkage unless it has internal linkage because of a previous declaration and provided it is not declared const. Objects declared const and not explicitly declared extern have internal linkage.
Solution 2:
The static
means that there will be one copy of VAL
created for each source file it is included in. But it also means that multiple inclusions will not result in multiple definitions of VAL
that will collide at link time. In C, without the static
you would need to ensure that only one source file defined VAL
while the other source files declared it extern
. Usually one would do this by defining it (possibly with an initializer) in a source file and put the extern
declaration in a header file.
static
variables at global level are only visible in their own source file whether they got there via an include or were in the main file.
Editor's note: In C++, const
objects with neither the static
nor extern
keywords in their declaration are implicitly static
.
Solution 3:
The static will mean you get one copy per file, but unlike others have said it's perfectly legal to do so. You can easily test this with a small code sample:
test.h:
static int TEST = 0;
void test();
test1.cpp:
#include <iostream>
#include "test.h"
int main(void) {
std::cout << &TEST << std::endl;
test();
}
test2.cpp:
#include <iostream>
#include "test.h"
void test() {
std::cout << &TEST << std::endl;
}
Running this gives you this output:
0x446020
0x446040