16. Preprocessing
16.1 Source File Inclusion
16.1.1 Use the preprocessor only for implementing include guards, and including header files with include guards
The preprocessor should only be used for including header files into other headers or the main source file, in order to form a translation unit. In particular only the following include directive forms should be used:
- #include <xyz>
- #include “xyz”
// @@+ Compliant +@@ #include <stddef> // @@- Non-Compliant -@@ #define MYHEADER "stddef" #include MYHEADER // @@- Non-Compliant -@@ #define CPU 1044 #ifndef CPU #error "no CPU defined" #endif
Additionally, an include guard should be present in each header file, to prevent multiple inclusions of the same file. A header file can take one of the following forms:
// only comments or whitespace #ifndef UNIQUE_IDENT_IN_PROJECT #define UNIQUE_IDENT_IN_PROJECT // @@+ Compliant +@@ // declarations #endif // only comments or whitespace // only comments or whitespace #if ! defined (UNIQUE_IDENT_IN_PROJECT) #define UNIQUE_IDENT_IN_PROJECT // @@+ Compliant +@@ // declarations #endif // only comments or whitespace
Where UNIQUE_IDENT_IN_PROJECT is chosen to uniquely represent the file which is being guarded. Preprocessor macros do not obey the linkage, lookup and function call semantics. Instead use constant objects, inline functions and function templates.
#include <cstdint> #include <algorithm> #define MIN(a,b) (((a) < (b)) ? (a) : (b)) void foo (int32_t i, int32_t j) { int32_t k = MIN(i,j); // @@- Non-Compliant -@@ k = std::min (i, j); // @@+ Compliant +@@ }
References
- HIC++ v3.3 - 14.11
- JSF AV C++ Rev C - 26
- JSF AV C++ Rev C - 27
- JSF AV C++ Rev C - 28
- JSF AV C++ Rev C - 29
- JSF AV C++ Rev C - 30
- JSF AV C++ Rev C - 31
- MISRA C++:2008 - 16-2-1
- MISRA C++:2008 - 16-2-2
16.1.2 Do not include a path specifier in filenames supplied in #include directives
Hardcoding the path to a header file in a #include directive may necessitate changes to source code when it is reused or ported. Alternatively, the directory containing the header file should be passed to the compiler on command line (e.g. -i or /i option).
// @@- Non-Compliant -@@ #include "../../component/include/api.h" // @@- Non-Compliant: may work on Windows -@@ #include "..\\..\\component\\include\\api.h" // @@+ Compliant +@@ #include "api.h"
References
- HIC++ v3.3 – 14.10
- MISRA C++:2008 – 16-2-5
16.1.3 Match the filename in a #include directive to the one on the filesystem
Some operating systems have case insensitive filesystems. Code initially developed on such a system may not compile successfully when ported to a case sensitive filesystem.
// @@- Non-Compliant -@@ #include <CStdDef> // @@+ Compliant +@@ #include <cstddef>
References
- HIC++ v3.3 – 14.12
16.1.4 Use <> brackets for system and standard library headers. Use quotes for all other headers
It is common practice that #include <…> is used for compiler provided headers, and #include “…” for user provided files. Adhering to this guideline therefore helps with the understandability and maintainability of the code.
// @@- Non-Compliant +@@ #include "cstddef" // @@+ Compliant +@@ #include <cstddef> // @@- Non-Compliant +@@ #include <types.h> // @@+ Compliant +@@ #include "types.h"
References
- HIC++ v3.3 – 14.9
16.1.5 Include directly the minimum number of headers required for compilation
Presence of spurious include directives can considerably slow down compilation of a large code base. When a source file is refactored, the list of included headers should be reviewed, to remove include directives which are no longer needed. Doing so may also offer an opportunity to delete from code repository source files that are no longer used in the project, therefore reducing the level of technical debt.
// @@+ Compliant +@@ #include <cstddef> // @@- Non-Compliant: not used -@@ #include <vector> // @@- Non-Compliant: duplicate -@@ #include <cstddef> void foo (std::size_t s);
To improve compilation time further, where possible, forward declaration of a user defined type should be preferred to including a header file that defines the type.
class C; // @@+ Compliant +@@ class D; // @@+ Compliant +@@ C foo (D); C * bar (D const &);
References
- HIC++ v3.3 – 17.20