缺少头文件保护¶
ID: cpp/missing-header-guard
Kind: problem
Security severity:
Severity: recommendation
Precision: high
Tags:
- efficiency
- maintainability
- modularity
- external/jsf
Query suites:
- cpp-security-and-quality.qls
一些头文件,例如定义结构或类的头文件,不能在同一个翻译单元中包含多次,因为这样做会导致重新定义错误。这样的头文件必须使用保护措施来防止多次包含带来的负面影响。类似地,如果头文件包含其他头文件,并且此包含图包含循环,则循环中的至少一个文件必须包含头文件保护措施才能打破循环。由于这些情况,所有头文件都应该使用保护措施,即使它们并非严格需要使用保护措施也是如此。
此外,大多数现代编译器包含由头文件保护措施触发的优化功能。如果头文件保护措施严格符合编译器预期的模式,则除第一次包含之外的所有包含将没有任何效果:文件不会从磁盘重新读取,也不会重新标记或重新预处理。这可以带来明显的,尽管很小的,编译时间改进。
建议¶
在文件中添加以下头文件保护措施之一(其中 HEADER_NAME
是从文件名派生的唯一标识符)
#ifndef HEADER_NAME
后面跟着#define HEADER_NAME
位于头文件的开头,最后使用匹配的#endif
结尾。#if !defined(HEADER_NAME)
后面跟着#define HEADER_NAME
位于头文件的开头,最后使用匹配的#endif
结尾。#pragma once
位于头文件中的任何位置。请注意,如果您要更新代码以匹配联合攻击战斗机空战车辆编码标准,则第一个选项是唯一合适的形式。
示例¶
以下头文件的作者试图使用头文件保护措施,但打错了一个字
#ifndef MY_HAEDER_H
#define MY_HEADER_H
/* ... contents of my_header.h ... */
#endif
在这样的情况下,MY_HAEDER_H
应该替换为 MY_HEADER_H
(注意 A
和 E
的位置互换)
#ifndef MY_HEADER_H
#define MY_HEADER_H
/* ... contents of my_header.h ... */
#endif
示例¶
以下头文件似乎有保护措施,但并不完全符合规则
#ifdef __linux__
#ifndef MY_LINUX_ONLY_HEADER_H
#define MY_LINUX_ONLY_HEADER_H
/* ... contents of my_linux_only_header.h ... */
#endif // MY_LINUX_ONLY_HEADER_H
#endif // __linux__
尽管前面头文件中的预处理器指令可以防止重复包含带来的错误,但并非所有编译器都足够智能,能够识别它已被保护。因此,编译器优化将受到限制。为了确保编译器能够识别保护措施,更改头文件,使保护措施成为最外层的指令
#ifndef MY_LINUX_ONLY_HEADER_H
#define MY_LINUX_ONLY_HEADER_H
#ifdef __linux__
/* ... contents of my_linux_only_header.h ... */
#endif // __linux__
#endif // MY_LINUX_ONLY_HEADER_H
示例¶
以下头文件随着时间的推移而不断发展,不同的作者在不同位置添加函数声明
void alpha();
#ifndef MY_FUNCTIONS_H
void beta();
#define MY_FUNCTIONS_H
void gamma();
void delta();
void epsilon();
#endif
void omega();
不幸的是,结果是某些声明位于初始 #ifndef
之前,某些声明位于 #ifndef
和 #define
之间,还有一些声明位于最终 #endif
之后。为了将此文件转换为正确保护的头文件,必须解决所有这三点问题
#ifndef MY_FUNCTIONS_H
#define MY_FUNCTIONS_H
void alpha();
void beta();
void gamma();
void delta();
void epsilon();
void omega();
#endif
参考资料¶
AV 规则 27 和 35,联合攻击战斗机空战车辆 C++ 编码标准。洛克希德·马丁公司,2005 年。