What exactly do C include guards do?
It's a preprocessor macro.
All of it is preprocessor syntax, that basically says, if this macro has not already been defined, define it and include all code between the #ifndef
and #endif
What it accomplishes is preventing the inclusion of file more than once, which can lead to problems in your code.
Your question:
And why is it okay to forget the include guard in which case we can also forgot adding #define HEADER_FILE?
It's OK to forget it because it's still legal C code without it. The preprocessor processes your file before it's compiled and includes the specified code in your final program if there's no logic specifying why it shouldn't. It's simply a common practice, but it's not required.
A simple example might help illustrate how this works:
Your header file, header_file.h
we'll say, contains this:
#ifndef HEADER_FILE
#define HEADER_FILE
int two(void){
return 2;
}
#endif
In another file (foo.c
), you might have:
#include "header_file.h"
void foo() {
int value = two();
printf("foo value=%d\n", value);
}
What this will translate to once it's "preprocessed" and ready for compilation is this:
int two(void){
return 2;
}
void foo() {
int value = two();
printf("foo value=%d\n", value);
}
All the include guard is accomplishing here is determining whether or not the header contents between the #ifndef ...
and #endif
should be pasted in place of the original #include
.
However, since that function is not declared extern
or static
, and is actually implemented in a header file, you'd have a problem if you tried to use it in another source file, since the function definition would not be included.
C: Extern variable declaration and include guards
Include guards are useful for preventing multiple delcarations or type definitions in a single translation unit, i.e. a .c file that is compiled by itself along with all of the headers it includes.
Suppose you have the following headers without include guards:
a.h:
struct test {
int i;
};
struct test t1;
b.h:
#include "a.h"
struct test *get_struct(void);
And the following main file:
main.c:
#include <stdio.h>
#include "a.h"
#include "b.h"
int main()
{
struct test *t = get_struct();
printf("t->i=%d\n", t->i);
return 0;
}
When the preprocessor runs on the, the resulting file will look something like this (neglecting the contents of stdio.h):
struct test {
int i;
};
struct test t1;
struct test {
int i;
};
struct test t1;
struct test *get_struct(void);
int main()
{
struct test *t = get_struct();
printf("t->i=%d\n", t->i);
return 0;
}
Because main.c includes a.h and b.h, and because b.h also includes a.h, the contents of a.h appear twice. This causes struct test
to be defined twice which is an error. There is no problem however with the variable t1
because each constitutes a tentative definition, and multiple tentative definitions in a translation unit are combined to refer to a single object defined in the resulting main.o.
By adding include guards to a.h:
#ifndef A_H
#define A_H
struct test {
int i;
};
struct test t1;
#endif
The resulting preprocessor output would be:
struct test {
int i;
};
struct test *get_struct(void);
int main()
{
struct test *t = get_struct();
printf("t->i=%d\n", t->i);
return 0;
}
Preventing the duplicate struct definition.
But now let's look at b.c which constitutes a separate translation unit:
b.c:
#include "b.h"
struct test *get_struct(void)
{
return &t1;
}
After the preprocessor runs we have:
struct test {
int i;
};
struct test t1;
struct test *get_struct(void);
struct test *get_struct(void)
{
return &t1;
}
This file will compile fine since there is one definition of struct test
and a tentative definition of t1
gives us an object defined in b.o.
Now we link a.o and b.o. The linker sees that both a.o and b.o contain an object called t1
, so the linking fails because it was defined multiple times.
Note here that while the include guards prevent a definition from appearing more than once in a single translation unit, it doesn't prevent it from happening across multiple translation units.
This is why t1
should have an external declaration in a.h:
extern struct test t1;
And a non-extern declaration in one .c file.
Include Guards in C
When config.h
includes debug.h
, debug.h
will try to include config.h
but since the CONFIG
guard macro will already have been defined, the retroactive "include" of config.h
will get skipped and the parsing will continue on the next line:
void somePrintingFunction(Config* conf);
without the Config
type having been defined.
As StoryTeller has pointed out, you can break the mutual dependency by forward declaring the Config_t
struct:
struct Config_t;
void somePrintingFunction(struct Config_t* conf);
Since C11, you can also do the typedef
since C11 can handle duplicated typedefs as long as they refer to the same type.
typedef struct Config_t Config;
void somePrintingFunction(Config* conf);
(Forward declarations of aggregates (structs or unions) don't allow you to declare objects of those types (unless a full definition has already been provided) but since C guarantees that all pointers to structs or unions must look the same, they are enough to allow you to start using pointers to those types.)
C Issue with include guards
#ifndef __BST_INCLUDED
#define __BST_INCLUDED__
//bunch of code here
#endif
This will not protect anything. For the simple reason that __BST_INCLUDED__
is not the same as __BST_INCLUDED
, and __BST_INCLUDED
never gets defined.
But also:
bst.h:22:13: error: conflicting types for ‘pruneBSTNode’
extern void pruneBSTNode(bst *tree,bstNode *node);
^
In file included from vbst.h:5:0,
from bstrees.c:7:
this error is not telling you that "the function has been included from another file", it's a completely unrelated error. The "included from" part is just telling you how the compiler got to the line displayed after it (which is missing from the question).
c++ include guards don't work, error
Include guards guard from a header file being included twice in a single file but here you have two different files. My advice is not to define any variables in header files. Instead declare them as extern
and define them in a separate cpp file where you include you header file. This way you will have only one definition but you will have them declared where you use them.
C language, proper usage of include guards
Include guards are used to prevent double definition in case an include file get included more than once.
The standard include files have the necessary include guards, so you need no include guards for them.
Your code should be:
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
The use of double include guards in C++
I am pretty sure that it is a bad practice to add another include guard like:
#ifndef __HEADER_A_HPP__
#include "header_a.hpp"
#endif
Here are some reasons why:
To avoid double inclusion it is enough to add a usual include guard inside the header file itself. It does the job well. Another include guard in the place of inclusion just messes the code and reduces readability.
It adds unnecessary dependencies. If you change include guard inside the header file you have to change it in all places where the header is included.
It is definitely not the most expensive operation comparing the whole compilation/linkage process so it can hardly reduce the total build time.
Any compiler worth anything already optimizes file-wide include-guards.
Related Topics
Which Is the Fastest Algorithm to Find Prime Numbers
Installing Opencv 2.4.3 in Visual C++ 2010 Express
Detecting Tcp Client Disconnect
How to Enable C++17 Compiling in Visual Studio
C++ Static Polymorphism (Crtp) and Using Typedefs from Derived Classes
Initialize Static Variables in C++ Class
C++11 Make_Pair With Specified Template Parameters Doesn't Compile
How to Specify a Pointer to an Overloaded Function
What Is the Purpose of the Most Vexing Parse
Function Parameter Evaluation Order
Variable Length Array (Vla) in C++ Compilers
How to Pass a Unique_Ptr Argument to a Constructor or a Function
Difference Between Void Main and Int Main in C/C++
Is Sizeof(Bool) Defined in the C++ Language Standard
Sorting Zipped (Locked) Containers in C++ Using Boost or the Stl