Pretty much every header file should follow the include guard idiom:
my-header-file.h
#ifndef MY_HEADER_FILE_H
#define MY_HEADER_FILE_H
// Code body for header file
#endif
This ensures that when you #include "my-header-file.h"
in multiple places, you don't get duplicate declarations of functions, variables, etc. Imagine the following hierarchy of files:
header-1.h
typedef struct {
…
} MyStruct;
int myFunction(MyStruct *value);
header-2.h
#include "header-1.h"
int myFunction2(MyStruct *value);
main.c
#include "header-1.h"
#include "header-2.h"
int main() {
// do something
}
This code has a serious problem: the detailed contents of MyStruct
is defined twice, which is not allowed. This would result in a compilation error that can be difficult to track down, since one header file includes another. If you instead did it with header guards:
header-1.h
#ifndef HEADER_1_H
#define HEADER_1_H
typedef struct {
…
} MyStruct;
int myFunction(MyStruct *value);
#endif
header-2.h
#ifndef HEADER_2_H
#define HEADER_2_H
#include "header-1.h"
int myFunction2(MyStruct *value);
#endif
main.c
#include "header-1.h"
#include "header-2.h"
int main() {
// do something
}
This would then expand to:
#ifndef HEADER_1_H
#define HEADER_1_H
typedef struct {
…
} MyStruct;
int myFunction(MyStruct *value);
#endif
#ifndef HEADER_2_H
#define HEADER_2_H
#ifndef HEADER_1_H // Safe, since HEADER_1_H was #define'd before.
#define HEADER_1_H
typedef struct {
…
} MyStruct;
int myFunction(MyStruct *value);
#endif
int myFunction2(MyStruct *value);
#endif
int main() {
// do something
}
When the compiler reaches the second inclusion of header-1.h, HEADER_1_H
was already defined by the previous inclusion. Ergo, it boils down to the following:
#define HEADER_1_H
typedef struct {
…
} MyStruct;
int myFunction(MyStruct *value);
#define HEADER_2_H
int myFunction2(MyStruct *value);
int main() {
// do something
}
And thus there is no compilation error.
Note: There are multiple different conventions for naming the header guards. Some people like to name it HEADER_2_H_
, some include the project name like MY_PROJECT_HEADER_2_H
. The important thing is to ensure that the convention you follow makes it so that each file in your project has a unique header guard.
If the structure details were not included in the header, the type declared would be incomplete or an opaque type. Such types can be useful, hiding implementation details from users of the functions. For many purposes, the FILE
type in the standard C library can be regarded as an opaque type (though it usually isn't opaque so that macro implementations of the standard I/O functions can make use of the internals of the structure). In that case, the header-1.h
could contain:
#ifndef HEADER_1_H
#define HEADER_1_H
typedef struct MyStruct MyStruct;
int myFunction(MyStruct *value);
#endif
Note that the structure must have a tag name (here MyStruct
— that's in the tags namespace, separate from the ordinary identifiers namespace of the typedef name MyStruct
), and that the { … }
is omitted. This says "there is a structure type struct MyStruct
and there is an alias for it MyStruct
".
In the implementation file, the details of the structure can be defined to make the type complete:
struct MyStruct {
…
};
If you are using C11, you could repeat the typedef struct MyStruct MyStruct;
declaration without causing a compilation error, but earlier versions of C would complain. Consequently, it is still best to use the include guard idiom, even though in this example, it would be optional if the code was only ever compiled with compilers that supported C11.
Many compilers support the #pragma once
directive, which has the same results:
my-header-file.h
#pragma once
// Code for header file
However, #pragma once
is not part of the C standard, so the code is less portable if you use it.
A few headers do not use the include guard idiom. One specific example is the standard <assert.h>
header. It may be included multiple times in a single translation unit, and the effect of doing so depends on whether the macro NDEBUG
is defined each time the header is included. You may occasionally have an analogous requirement; such cases will be few and far between. Ordinarily, your headers should be protected by the include guard idiom.