Why do the include guards not prevent multiple definitions of this function like they do for other header items?
The process of creating an executable from a C++ program consists of three stages:
- Preprocessing
- Compilation &
- Linking
Preprocessing: the preprocessor directives like macros etc are replaced during this stage.
Compilation is converting the source code in to object code by checking for language semantics.
Linking is to link all the generated object code together to form an executable.
Header guards prevent the contents of the header to be included multiple times in the same translation unit during preprocessing. They do not prevent the contents to be included in different translation units. When you include this header file in different translation units, each of these units will have a definition of this function.
The compiler compiles each translation unit separately to produce a separate object file(.o), each of those .o files will have an copy of this function definition. When the linker tries to link to the function definition at time of generating the .exe
it finds multiple definitions of the same functions, thereby causing confusion as to which one to link to. To avoid this problem the standard defines a rule known as the One defintion rule(ODR), which forbids multiple definitions of the same entity.
As you see including the function definition in the header file and including that header file in multiple translation units violates the ODR.
The usual way to do this is to provide the declaration in the header file and the definition in one and only one source file.
Why does the static word resolve this when static is supposed to prevent names from visibility in other translation units?
When you add the keyword static
to the function each translation unit will have its own copy of the function. By default functions have external linkage but static
forces the function to have an internal linkage. Thus the definition is not visible to different translation units. Each instance of such a function is treated as a separate function(address of each function is different) and each instance of these functions have their own copies of static local variables & string literals. Note that this increases the size of your executable considerably.
If you want to include the function definition in a header file. There are 3 ways to do it:
- Mark the function as
inline
or
- Mark the function as
static
or
- Put the function in an unnamed namespace.
Note that #1
and #2
do the same as mentioned in second answer above.
With #3
the standard relaxes the ODR for inline functions and allows each translation unit to have its own definition(provided all definitions are same).
So if you really want to put a function definition in header #1
is the right way to do it.