背景
我有 C 项目,它有一个配置头文件,例如:
// config.h
#define FEATURE_1_AVAILABLE 1
#define FEATURE_2_AVAILABLE 0
#define FEATURE_3_AVAILABLE 1
模块使用这些标志来包含/排除build中的功能:
#include "config.h"
void foo(void) {
...
#if FEATURE_1_AVAILABLE
useFeature1();
#endif
...
不同版本的config.h
版本有不同版本。
问题
#include "config.h"
被意外删除,因此功能即使在配置中启用也无法激活。
不幸的是,#if FEATURE_1_AVAILABLE
在未定义时会默默评估为0
。如果没有定义,我需要一个错误。
选项1
我可以添加额外的'如果已定义'测试每种情况。
#ifndef FEATURE_1_AVAILABLE
#error No feature 1
#elif FEATURE_1_AVAILABLE
useFeature1();
#endif
缺点是可以在模块中的多个不同位置测试一个功能标志,并且添加多个预处理器行不会使代码更漂亮。
选项2
在模块的开头添加单个测试:
#ifndef FEATURE_1_AVAILABLE
#error No feature 1
#endif
但由于与#include "config.h"
相同的原因,这可能会丢失/遗忘。
选项3
将标志定义为宏:
#define FEATURE_1_AVAILABLE() 1
并用作:
#if FEATURE_1_AVAILABLE()
不幸的是,如果你忘了括号,这也会无声地失败:
#if FEATURE_1_AVAILABLE
选项X
有更好的选择吗?如果未定义符号或未正确写入符号,则会在编译时给出错误消息。并且希望不会使代码看起来不可维护的预处理程序混乱。
其他事项
答案 0 :(得分:4)
另一种解决方案是让编译器在未定义被评估的宏时发出警告。
例如,gcc
有-Wundef
选项(未包含在-Wall
中):
#if FEATURE_1_AVAILABLE
useFeature1();
#endif
这会发出警告(添加-Werror
以使其成为错误):
tst.c:6:9: warning: "FEATURE_1_AVAILABLE" is not defined [-Wundef]
#if FEATURE_1_AVAILABLE
此选项也适用于其他编译器,例如: g。,clang
和icc
。
答案 1 :(得分:0)
我知道它是being frowned upon,但对于较小的C项目,使用一个项目范围的包含文件(例如myproject.h
)与您的{{{{{ 1}}指令(如#include ..
),然后在每个源文件的顶部只有 #include "config.h"
。
意外忘记这个单#include "myproject.h
通常会立即破坏编译,因此不会被忽视。
或者,您可以在#include
(并且只在那里)放置一个必要的#include
(比如#include assert.h
),再次在您忘记包含它时惹恼编译器/链接器< / p>