关于缺少预处理器符号的编译器警告

use*_*733 4 c c-preprocessor preprocessor-directive

背景

我有一个带有配置头文件的C项目,例如:

// config.h
#define FEATURE_1_AVAILABLE      1
#define FEATURE_2_AVAILABLE      0
#define FEATURE_3_AVAILABLE      1
Run Code Online (Sandbox Code Playgroud)

模块使用这些标志在构建中包括/排除功能:

#include "config.h"
void foo(void) {
    ...
    #if FEATURE_1_AVAILABLE
    useFeature1();
    #endif
    ...
Run Code Online (Sandbox Code Playgroud)

有不同版本的config.h不同版本。

问题

#include "config.h" 被意外删除,因此即使在config中启用了该功能,该功能也未处于活动状态。

不幸的是,它会#if FEATURE_1_AVAILABLE默默地评估0未定义的时间。因此,如果未定义,我需要一个错误。

选项1

我可以在每个条件上添加额外的“如果定义”测试。

#ifndef FEATURE_1_AVAILABLE
    #error No feature 1  
#elif FEATURE_1_AVAILABLE
    useFeature1();
#endif
Run Code Online (Sandbox Code Playgroud)

缺点是一个功能标记可能会在模块中的许多不同位置进行测试,并且添加多条预处理程序行不会使代码更漂亮。

选项2

在模块的开头添加单个测试:

#ifndef FEATURE_1_AVAILABLE
    #error  No feature 1  
#endif
Run Code Online (Sandbox Code Playgroud)

但这可能会因为相同的原因而丢失/遗忘#include "config.h"

选项3

将标志定义为宏:

#define FEATURE_1_AVAILABLE()      1
Run Code Online (Sandbox Code Playgroud)

并用作:

#if FEATURE_1_AVAILABLE()
Run Code Online (Sandbox Code Playgroud)

不幸的是,如果您忘记括号,这也将无声地失败:

#if FEATURE_1_AVAILABLE
Run Code Online (Sandbox Code Playgroud)

选项X

有更好的选择吗?如果未定义符号或书写不正确,则会在编译时给出错误消息。并希望不会使代码看起来无法维护的预处理器混乱。

其他事情

  • 运行时检查是不可能的。禁用的功能不得包含在二进制文件中。
  • 功能必须在文件中定义。将它们定义为全局编译器选项还有其他问题。
  • 这适用于嵌入式系统。其中一些功能需要硬件才能工作,并且测试非常耗时。因此,最好在编译时出错。

oua*_*uah 5

另一个解决方案是让编译器在未定义要评估的宏时警告您。

随着gcc例如存在-Wundef选项(不包括在-Wall):

#if FEATURE_1_AVAILABLE
useFeature1();
#endif
Run Code Online (Sandbox Code Playgroud)

这给出警告(添加-Werror使其成为错误):

tst.c:6:9: warning: "FEATURE_1_AVAILABLE" is not defined [-Wundef]
     #if FEATURE_1_AVAILABLE
Run Code Online (Sandbox Code Playgroud)

其他编译器(例如clang和)也可以使用此选项icc

  • 请注意,此警告会产生很多误报,尤其是在使用预处理器宏进行平台兼容性检查的系统上。 (2认同)