【问题标题】:How can I generate a list of #define values from C code?如何从 C 代码生成#define 值列表?
【发布时间】:2010-12-30 17:46:17
【问题描述】:

我的代码中有很多复杂的#define 错误代码,由于它们嵌套在多个级别中,因此不容易解码。

有没有什么优雅的方法可以得到一个带有最终数值(或其他任何值)的#defines 列表?

举个例子:

<header1.h>
#define CREATE_ERROR_CODE(class, sc, code) ((class << 16) & (sc << 8) & code)
#define EMI_MAX 16

<header2.h>
#define MI_1 EMI_MAX

<header3.h>
#define MODULE_ERROR_CLASS MI_1
#define MODULE_ERROR_SUBCLASS 1
#define ERROR_FOO CREATE_ERROR_CODE(MODULE_ERROR_CLASS, MODULE_ERROR_SUBCLASS, 1)

我将有大量类似的 #defines 匹配 ERROR_[\w_]+ 我想枚举,以便我始终拥有程序可以输出的当前错误代码列表。我需要数值,因为这就是程序将打印出来的所有内容(不,它不是打印字符串的选项)。

对 gcc 或任何其他编译器的建议会有所帮助。

【问题讨论】:

  • 您是否考虑过使用实常数而不是#defines?
  • 将代码更改为 const 是不切实际的,因为它是从上游源继承而来的。

标签: c gcc c-preprocessor


【解决方案1】:

GCC 的 -dM preprocessor option 可能会得到你想要的。

【讨论】:

  • 这似乎是正确的想法,但它并没有扩展我的宏。我尝试运行 `gcc -E -Wp,-dD header3.h 并最终得到与上面定义的完全相同的#define。
  • @djs: 是的,并不是一直如此。 -dM 将输出一个宏列表,您可以将其输入脚本以生成扩展。
  • 最终结果是我有一个预处理器可以扩展的类似函数的宏列表,但我当然不想这样做。所以我需要一些方法来扩展它们......
【解决方案2】:

我认为解决方案是@nmichaels 和@aschepler 的答案的组合。

使用 gcc 的 -dM 选项获取宏列表。 使用 perl 或 awk 或其他任何东西从这个列表中创建 2 个文件:

1) Macros.h,仅包含#defines。

2) Codes.c,其中包含

#include "Macros.h"

ERROR_FOO = "ERROR_FOO"
ERROR_BAR = "ERROR_BAR"

(即:将每个 #define ERROR_x 提取到包含宏和字符串的行中。

现在运行gcc -E Codes.c。那应该创建一个扩展了所有宏的文件。输出应该类似于

1 = "ERROR_FOO"
2 = "ERROR_BAR"

我手边没有 gcc,所以没有测试过这个...

【讨论】:

  • 我试过了,只用了 6 个 perl 的处理,我终于得到了一个排序的数值列表!这个解决方案的一个问题是 gcc -E -P 给了我一个包含所有预处理头的大文件。我删除了 -P 并只取了“# 2 Codes.c 2”之后的行。解决这个问题,我认为你会赢得赏金......
  • 完成。 -P 应该“禁止在预处理器的输出中生成线标记”,这对于使文件看起来更干净似乎很有用。哦,好吧。
  • 我在这里错过的关键概念是我不能只预处理标头,我需要运行一个引用这些常量的 C 文件来实际扩展它。我错过的另一部分是我自己弄清楚的:我只能得到一个算术表达式,我需要对其进行评估。从技术上讲,我想我需要编译它,但我作弊并将其传递给 perl eval。
【解决方案3】:

程序'coan' 看起来像您所追求的工具。它有'defs'子命令,描述为:

defs [选项...] [文件...] [目录...]

根据选项从输入文件中选择#define#undef指令,并根据选项在标准输出上报告。

有关选项的更多信息,请参阅引用的 URL。获取代码here

【讨论】:

  • 有趣的应用程序。直到我发现它不支持类函数宏的扩展时,我才感到非常兴奋。虽然有一个缺陷可以解决这个问题,所以也许有一天它会成为答案。
【解决方案4】:

如果你有一个完整的宏列表,并且都是数字的,你可以为此目的编译并运行一个简短的程序:

#include <header3.h>
#include <stdio.h>

#define SHOW(x) printf(#x " = %lld\n", (long long int) x)

int main(void) {
    SHOW(ERROR_FOO);
    /*...*/
    return 0;
}

正如@nmichaels 所提到的,gcc 的-d 标志可能有助于显示该宏列表。

【讨论】:

    【解决方案5】:

    这里有一个小创意解决方案:

    编写一个程序,用正则表达式匹配所有标识符(如 .NET 中的 \#define :b+(?&lt;NAME&gt;[0-9_A-Za-z]+):b+(?&lt;VALUE&gt;[^(].+)$),然后让它创建另一个仅匹配名称的 C 文件:

    void main() {
        /*my_define_1*/ my_define_1;
        /*my_define_2*/ my_define_2;
        //...
    }
    

    然后使用 /C /P 选项(对于 VC++)预处理您的文件,您应该将所有这些替换为值。然后使用另一个正则表达式交换内容,并将 cmets 放在 #define 格式的值之前——现在你有了 #define 的列表!

    (你可以用 GCC 做类似的事情。)

    【讨论】:

      【解决方案6】:

      有没有什么优雅的方法可以得到一个带有最终数值的#defines列表

      对于各种级别的优雅,有点。

      #!/bin/bash
      
      file="mount.c";
      for macro in $(grep -Po '(?<=#define)\s+(\S+)' "$file"); do
          echo -en "$macro: ";
          echo -en '#include "'"$file"'"\n'"$macro\n" | \
          cpp -E -P -x c ${CPPFLAGS} - | tail -n1;
      done;
      

      并非万无一失(#define \ \n macro(x) ... 不会被抓到 - 但我见过的任何风格都没有)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-07-30
        • 1970-01-01
        • 1970-01-01
        • 2012-03-04
        • 2020-07-25
        • 2015-10-25
        • 2017-05-11
        • 1970-01-01
        相关资源
        最近更新 更多