【问题标题】:Is there a C pre-processor which eliminates #ifdef blocks based on values defined/undefined?是否有一个 C 预处理器可以根据定义/未定义的值消除 #ifdef 块?
【发布时间】:2010-10-06 05:35:51
【问题描述】:

原始问题

我想要的不是标准的 C 预处理器,而是它的变体,它可以从某个地方接受 - 可能是通过 -DNAME1 和 -UNAME2 选项的命令行 - 定义了哪些宏的规范,并且会然后消除死代码。

通过一些示例可能更容易理解我所追求的:

#ifdef NAME1
#define ALBUQUERQUE "ambidextrous"
#else
#define PHANTASMAGORIA "ghostly"
#endif

如果命令使用“-DNAME1”运行,输出将是:

#define ALBUQUERQUE "ambidextrous"

如果使用“-UNAME1”运行命令,则输出为:

#define PHANTASMAGORIA "ghostly"

如果该命令没有任何选项运行,则输出将与输入相同。

这是一个简单的案例 - 我希望代码也可以处理更复杂的案例。

用一个真实但仍然简单的例子来说明:

#ifdef USE_VOID
#ifdef PLATFORM1
#define VOID void
#else
#undef VOID
typedef void    VOID;
#endif /* PLATFORM1 */
typedef void *  VOIDPTR;
#else
typedef mint     VOID;
typedef char *  VOIDPTR;
#endif /* USE_VOID */

我想用-DUSE_VOID -UPLATFORM1 运行命令并获得输出:

#undef VOID
typedef void    VOID;
typedef void *  VOIDPTR;

另一个例子:

#ifndef DOUBLEPAD
#if (defined NT) || (defined OLDUNIX)
#define DOUBLEPAD 8
#else
#define DOUBLEPAD 0
#endif /* NT */
#endif /* !DOUBLEPAD */

理想情况下,我想使用-UOLDUNIX 运行并获得输出:

#ifndef DOUBLEPAD
#if (defined NT)
#define DOUBLEPAD 8
#else
#define DOUBLEPAD 0
#endif /* NT */
#endif /* !DOUBLEPAD */

这可能会影响我的运气!

动机:包含大量条件代码的大型古老代码库。许多条件不再适用 - 例如,OLDUNIX 平台不再制造且不再受支持,因此无需在代码中引用它。其他条件始终为真。例如,通过条件编译添加功能,以便单个版本的代码可用于该功能不可用的旧版本软件和可用(或多或少)的新版本。最终,不再支持没有该功能的旧版本 - 一切都使用该功能 - 因此应该删除该功能是否存在的条件,并且“当功能不存在时”代码也应该删除。我想要一个工具来自动完成这项工作,因为它比手动完成更快、更可靠(当代码库包含 21,500 个源文件时,这一点相当重要)。

(该工具的一个非常聪明的版本可能会读取#include'd 文件以确定控制宏(在命令行上由 -D 或 -U 指定的那些)是否在这些文件中定义。我不确定除了作为备份诊断之外,这是否真的有用。但是,无论它做什么,伪预处理器都不能逐字扩展宏或包含文件。输出必须是类似于输入代码的源代码,但通常比输入代码更简单。)

状态报告(一年后)

经过一年的使用,我对所选答案推荐的'sunifdef'感到非常满意。它还没有出错,我也不希望它出错。我对它的唯一质疑是风格。给定一个输入,例如:

#if (defined(A) && defined(B)) || defined(C) || (defined(D) && defined(E))

并使用“-UC”运行(C 从未定义),输出为:

#if defined(A) && defined(B) || defined(D) && defined(E)

这在技术上是正确的,因为 '&&' 比 '||' 绑定得更紧密,但这是一个公开的混淆邀请。我更希望它在 '&&' 条件集周围包含括号,就像原来的一样:

#if (defined(A) && defined(B)) || (defined(D) && defined(E))

但是,鉴于我必须使用的一些代码晦涩难懂,因为这是最大的挑剔,这是一种强烈的赞美;这对我来说是很有价值的工具。


街区新来的人

在检查了上述信息中包含的 URL 后,我看到(正如预测的那样)有一个名为 Coan 的新程序是 'sunifdef' 的后继程序。它在 SourceForge 上可用,自 2010 年 1 月以来一直可用。我会检查它...今年晚些时候,或者明年,或者某个时候,或者永远不会有进一步的报告。

【问题讨论】:

  • 感谢您的建议 - 不,这不是我需要的。我知道如何查看编译器看到的内容(前几天我花了几个小时查看 37,000 行扩展输出,以找出出现问题的原因)。我希望 #include 和其他行保留,并且宏未展开。

标签: c++ c preprocessor


【解决方案1】:

我对 C 完全一无所知,但听起来您正在寻找类似 @​​987654321@ 的东西。请注意,它自 2000 年以来一直没有更新,但有一个名为 "Son of unifdef" (sunifdef) 的继任者。

【讨论】:

  • 两个都下载了。将 sunifdef 移植到 Solaris 10 时遇到了一些问题;我已将该信息转发给开发人员。现在看起来很有希望,我已经解决了这些问题。谢谢。
  • sunifdef 工作得非常好 - 并且揭示了代码库中迄今为止未实现的堕落深度。那好吧;它最终会变得更干净。感谢您的提示,Jörg。
  • 不客气。我喜欢干净、漂亮、富有表现力的代码——我很高兴能帮助你让世界变得更美好:-)
  • 在类似的问题here 中还要注意unifdef 现在正在积极维护中,并在 Linux 内核中使用。
【解决方案2】:

你也可以试试这个工具http://coan2.sourceforge.net/

这样的东西会删除 ifdef 块:

coan source -UYOUR_FLAG --filter c,h --recurse YourSourceTree

【讨论】:

  • 欢迎来到 Stack Overflow。请尽快阅读FAQ。 Coan 在主要问题中被称为“街区新来的”。
【解决方案3】:

几年前我使用 unifdef 来解决您描述的那种问题,并且效果很好。即使它自 2000 年以来没有更新,预处理器 ifdefs 的语法从那时起也没有发生实质性的变化,所以我希望它仍然会做你想做的事。我想可能有一些编译问题,尽管这些包是最近才出现的。

我没用过sunifdef,所以不能直接评论。

【讨论】:

    【解决方案4】:

    大约在 2004 年,我编写了一个工具,它完全符合您的要求。我一直没有时间分发该工具,但可以在这里找到代码:

    http://casey.dnsalias.org/exifdef-0.2.zip(这是一个 dsl 链接)

    它大约有 1.7k 行,并实现了足够的 C 语法来使用 bison 和 flex 解析预处理器语句、cmets 和字符串。

    【讨论】:

      【解决方案5】:

      如果您需要类似于预处理器的东西,灵活的解决方案是Wave(来自 boost)。它是一个旨在构建类似 C 预处理器的工具(包括 C++03 和 C++0x 预处理器)的库。由于它是一个库,因此您可以挂钩它的输入和输出代码。

      【讨论】:

      • 谢谢。这看起来很有趣,但需要打包来完成这项工作,而 sunifdef 已经打包并且做得很好。我已添加 URL - 感谢您提供信息。
      猜你喜欢
      • 1970-01-01
      • 2013-06-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-10
      • 2012-02-02
      相关资源
      最近更新 更多