如何逐步扩展C预处理器宏?

4
gdb有一个文档记录的但尚未实现的命令(截至8.3版本)叫做macro expand-once。其目的是执行一步宏扩展而不递归到其他宏调用中。根据文档

macro expand-onceexpression
macro exp1expression

(此命令尚未实现。)显示显式出现在expression中的预处理器宏调用的扩展结果。该扩展中出现的宏调用保持不变。该命令使您能够更清楚地看到特定宏的效果,而不会被进一步的扩展所混淆。由于GDB只是扩展宏而不解析结果,因此expression不必是有效表达式;它可以是任何令牌字符串。

真是个难以忍受的诱惑!这种功能将为概念上简单的迭代gdb脚本奠定基础,以输出宏扩展的每个步骤,这正是我需要的信息。无论它是否由gdb提供对我来说都是次要的,但我确实希望以某种方式自动化这个过程——我已经厌倦了查找代码并手写所有内容。

gdbmacro expand-once命令实现之前,是否有其他编程方式可以逐步展开C预处理器宏?我想这可能是通过从cpp中转储宏定义,解析输出并创建一种“调用图”来实现的,但也许我太天真了。

注意:虽然悬赏说明声明“仅提供构建潜在解决方案的库函数的引用将不获得悬赏”,但如果悬赏期结束时未发布悬赏资格的解决方案,则仍可能接受此类答案。

2个回答

2

你可以使用wave(boost库的一部分):

文档中的示例:

文件test.cpp:

    // test.cpp
    #define X(x)          x
    #define Y()           2
    #define CONCAT_(x, y) x ## y
    #define CONCAT(x, y)  CONCAT_(x, y)
    #pragma wave trace(enable)
    // this macro expansion is to be traced
    CONCAT(X(1), Y())     // should expand to 12
    #pragma wave trace(disable)

运行wave -t test.trace test.cpp会创建一个文件test.trace:

test.cpp:8:1: CONCAT(X(1), Y())
  test.cpp:5:9: 参见宏定义:CONCAT(x,y)
  调用时
  [
    x = X(1)
    y = Y()
  ]
  [
    test.cpp:2:9: 参见宏定义:X(x)
    调用时
    [
      x = 1
    ]
    [
      1
      重新扫描
      [
        1
      ]
    ]
    test.cpp:3:9: 参见宏定义:Y()
    [
      2
      重新扫描
      [
        2
      ]
    ]
    CONCAT_(1, 2)
    重新扫描
    [
      test.cpp:4:9: 参见宏定义:CONCAT_(x,y)
      调用时
      [
        x = 1
        y = 2
      ]
      [
        12
        重新扫描
        [
          12
        ]
      ]
      12
    ]
  ]

1
根据存储库历史记录,以下是来自ChangeLog的摘录,可以追溯到2002年:

2002-05-16 Jim Blandy

添加手动扩展宏并显示其定义的命令。

然而,似乎从未跟进过。
根据GCC文档,

宏展开是一项棘手的操作,充满了许多恶心的细节和情况,这些情况会使您认为优化预处理器的扩展算法的聪明方法在相当微妙的方式上变得错误。

也许这就是为什么它从未被实现的原因?
预处理器以标记化形式存储宏的扩展。这样做可以避免在扩展期间重复进行词法分析,但平均而言会略微增加内存消耗。这些标记被连续地存储在内存中,因此您只需要一个指向第一个标记的指针和一个标记计数就可以获取宏的替换列表。
理论上,通过指针算术可以逐个遍历每个标记;然而,如果这么简单,我无法想象为什么它还没有被实现。

1
理论上,通过指针算术运算逐个遍历每个标记是可能的;然而,如果它如此简单,我无法想象为什么它还没有被实现。这似乎是一个值得在邮件列表中讨论的问题。假期期间,我会在那里发布并回报。 - eeowaa
我大约10天前在邮件列表上发布了帖子,但没有得到回复。 - eeowaa
你能否在档案中包含一个链接? - oxr463
1
我从来不知道在邮件列表中发布时应该包含多少细节,所以通常都很简略。也许语气有问题,这就是为什么我没有得到回复的原因。这是链接:https://sourceware.org/ml/gdb/2019-12/msg00058.html - eeowaa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接