Let’s start the series with something simple: the basic structure of header files and why and how to protect against multiple inclusion.
The basic use of header files is to provide symbol declarations for functions and globals. Because multiple declarations of a given symbol in a single translation unit are a syntax error, you have to defensively structure your header files to not redefine anything in case they are included multiple times.
Keep in mind that you just cannot prevent header files from being included more than once unless you were to forbid header files themselves from including other header files… and doing that would be suboptimal at best as we shall see in a future post on self-containment.
Just follow this pattern and encapsulate the whole contents of the whole header file within a guard:
#if !defined(PROJECT_MODULE_H) #define PROJECT_MODULE_H ... all header file contents go here ... #endif /* !defined(PROJECT_MODULE_H) */
Easy, but there are two important details to keep in mind:
The first is to properly scope the guard names. These names must be unique within your project and within any project that may ever include them. Therefore, it is good practice to always prefix your guard names with the name of your project and follow them by the name of the module.
The second is to not be clever. Compilers expect the structure above in order to apply optimizations against multiple inclusions of a single file. If you break the pattern, you can unknowingly incur higher build times. For example, see GCC’s documentation on this topic for details.
As with any rule there is an exception: not all header files can safely be included more than once. If a header file defines a static symbol or helper function, you have to ensure that it is not pulled in from more than one place.
Yes, the compiler would detect this on its own but, for readability purposes, your header file should explicitly state this fact. Use this other pattern instead:
#if defined(PROJECT_MODULE_H) #error "Must only be included once and only from .c files" #endif #define PROJECT_MODULE_H ... all header file contents go here ...
But when can this happen? Very rarely, really. A specific case of the above would be a header file providing helper functions for testing, both their definitions and their implementation. Theoretically, you could split the two into a traditional header file and a source file, compile them separately and link them together with each test program you write. However, doing so may complicate your build unnecessarily. (Ab)using a single header file can make things easier to handle. See this test_utils.hpp example.