PRE32-C. 不要在触发函数宏中使用预编译指令
宏的参数中不能包含预编译指令,比如 #define
, #ifdef
, 和#include
. 根据C语言标准,6.10.3,第11段[ISO/IEC 9899:2011],这样做会引起 未定义的行为
The sequence of preprocessing tokens bounded by the outside-most matching parentheses forms the list of arguments for the function-like macro. The individual arguments within the list are separated by comma preprocessing tokens, but comma preprocessing tokens between matching inner parentheses do not separate arguments. If there are sequences of preprocessing tokens within the list of arguments that would otherwise act as preprocessing directives, the behavior is undefined.
同时参见 未定义行为 93.
这个规则同样适用于将预编译指令作为任何函数的参数,因为不知道函数是否是用宏实现。这包括所有的标准库函数,比如 memcpy()
, printf()
, 和assert()
,因为不知道这些标准库函数是否用宏实现(C11, 7.1.4,第1段)。
不遵从规范的示例代码
在这个不遵从规范的示例代码中[GCC Bugs],编程人员使用了预处理指令来指定平台相关的参数。然而,如果memcpy()
是通过宏来实现的,那么这个代码就会产生未定义行为。
#include <string.h>
void func(const char *src) {
/* Validate the source string; calculate size */
char *dest;
/* malloc() destination string */
memcpy(dest, src,
#ifdef PLATFORM1
12
#else
24
#endif
);
/* ... */
}
遵从规范的解决方案
#include <string.h>
void func(const char *src) {
/* Validate the source string; calculate size */
char *dest;
/* malloc() destination string */
#ifdef PLATFORM1
memcpy(dest, src, 12);
#else
memcpy(dest, src, 24);
#endif
/* ... */
}
风险评估
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
PRE32-C | Low | Unlikely | Medium | P2 | L3 |
参考文献
[GCC Bugs] | "Non-bugs" |
---|---|
[ISO/IEC 9899:2011] | 6.10.3, "Macro Replacement" |