头文件不应缺少守卫
3.4.1 ID_missingHeaderGuard
以 .h 或 .hpp 为扩展名的头文件应包含头文件守卫。
示例:
// Header file foo.h
#ifndef LIBRARY_FOO_H
#define LIBRARY_FOO_H
....
#endif
例中 foo.h 是“Library”模块中的头文件,宏 LIBRARY_FOO_H 即可作为它的守卫,保证头文件被重复引入也不会出现问题,守卫名称不可有重复,建议守卫名称遵循“模块名_文件名”的形式。
#pragma once 指令也可作为头文件守卫,但并不是 C/C++ 的标准方式,只是多数编译器均有支持。这种方式由编译器维护一个列表,引入头文件时,如果发现文件中有 #pragma once 指令就将文件路径加入列表,当这个文件再次被 include 时便不会加载,而宏守卫的方式仍然要对文件进行预编译,所以 #pragma once 方式在编译效率上会更高一些。
宏守卫用宏名区分头文件,所以不能有重复。宏的引入可以使相关设定更灵活,比如声明头文件之间的依赖或排斥关系,如果 bar.h 依赖 foo.h,在 #include "bar.h" 之前必须 #include "foo.h",可在 bar.h 中设置:
// Header file bar.h
#ifndef LIBRARY_FOO_H
#error foo.h should be included first
#endif
这样如果不满足条件无法通过编译。
本规则建议使用宏守卫的方式,但 #pragma once 方法也是惯用写法,不妨通过配置项决定其是否合规。
配置
allowPragmaOnce: 是否允许 #pragma once 作为头文件守卫
参考
C++ Core Guidelines SF.8
MISRA C 2004 19.15
MISRA C++ 2008 16-2-3