【问题标题】:Compiler warning about missing preprocessor symbol [duplicate]关于缺少预处理器符号的编译器警告[重复]
【发布时间】:2015-01-23 08:58:38
【问题描述】:

背景

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

// config.h
#define FEATURE_1_AVAILABLE      1
#define FEATURE_2_AVAILABLE      0
#define FEATURE_3_AVAILABLE      1

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

#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

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

其他事情

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

【问题讨论】:

  • 找到负责删除包含的人,然后将那个人放在头上。如果您确实需要在所有源文件中包含该特定头文件,那么所有开发人员都需要知道它。此外,自动化单元测试应该会自动检测到此类问题(您确实进行过自动化单元测试吗?),并且在程序到达客户之前就已修复。
  • @JoachimPileborg 但我不想打自己 :) 它被意外删除了。关于单元测试:正如我所写,在没有硬件的情况下测试其中一些是不可能的。因此,在编译时检测到此类错误时,修复成本会更低。
  • @JimBalter 快速查看可能是骗人的。如果是,我会进一步查看并关闭它。

标签: c c-preprocessor preprocessor-directive


【解决方案1】:

另一种解决方案是让编译器在未定义正在评估的宏时发出警告。

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

此选项也可用于其他编译器,例如。例如,clangicc

【讨论】:

  • 请注意,此警告可能会产生很多误报,尤其是在使用预处理器宏进行平台兼容性检查的系统上。
  • @JoachimPileborg 这是我通常在我自己的程序中使用的一个选项(但前提是我从其他第三方程序/库获得零警告)
  • 这是一个很好的建议,但在我的情况下,第 3 方库会有很多误报。
【解决方案2】:

我知道它是 being frowned upon,但对于较小的 C 项目,使用所有 #include .. 指令(如#include "config.h") ,然后 only #include "myproject.h 在每个源文件的顶部。

不小心忘记这个#include 通常会立即中断编译,因此不会被忽视。

或者,您可以在您的config.h 中添加一个必不可少的#include(例如#include assert.h)(并且仅在此处),当您忘记包含它时再次惹恼编译器/链接器

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-03-18
    • 2023-03-03
    • 2011-11-23
    • 2019-07-09
    • 2015-09-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多