Why include guards do not prevent multiple function definitions? [duplicate]
The linker reports duplicate symbol on this:
#ifndef testttt
#define testttt
void anything(){
std::cout<<"hellooooooo";
}
#endif
Because it is inside the include guards, I would expect that this function is only defined once. But apparently not.
I know I can put the word static
in front of it and then it will work (which I still find ironic, since static is supposed to give it internal linkage, yet the function can be used from multiple cpp files).
So I guess my two-part question is: 1) Why do the include guards not prevent multiple definitions of this function like they do for other header items, and 2) Why does the static
word resolve this when static is supposed to prevent names from visibility in other translation units? I add it, and I can actually call this function from anywhere that includes this header file.
"1) Why do the include guards not prevent multiple definitions of this function like they do for other header items"
Because each translation unit (i.e. .cpp file) is processed separately and goes through the same conditional. Translation units won't share the preprocessor definitions encountered by other translation units. This means that all the translation units that will process that header will include a definition for that function. Of course, the linker will then complain that the same function has multiple definitions.
"2) Why does the static word resolve this when static is supposed to prevent names from visibility in other translation units?"
Because the static
keyword makes a private copy of that function for each translation unit.
If you want that function to be defined in a shared header, however, you should rather mark it as inline
, which will solve your problem and will make the preprocessor guards unnecessary.
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.