【问题标题】:During C macro expansion, is there a special case for macros that would expand to "/*"?在 C 宏扩展期间,是否存在将扩展为“/*”的宏的特殊情况?
【发布时间】:2010-11-12 13:50:52
【问题描述】:

这是一个相关的例子。这显然是无效的C,但我这里只是处理预处理器,所以代码实际上不必编译。

#define IDENTITY(x) x
#define PREPEND_ASTERISK(x) *x
#define PREPEND_SLASH(x) /x

IDENTITY(literal)
PREPEND_ASTERISK(literal)
PREPEND_SLASH(literal)
IDENTITY(*pointer)
PREPEND_ASTERISK(*pointer)
PREPEND_SLASH(*pointer)

在上面运行 gcc 的预处理器:

gcc -std=c99 -E macrotest.c

这会产生:

(...)

literal
*literal
/literal
*pointer
**pointer
/ *pointer

请注意最后一行的多余空格。

对我来说,这看起来像是一个防止宏扩展为“/*”的功能,我敢肯定这是出于好意。但乍一看,我在 C99 标准中找不到与此行为有关的任何内容。再说一次,我对 C 缺乏经验。有人可以对此有所了解吗?这是在哪里指定的?我猜想遵循 C99 的编译器不应该仅仅因为它可能会防止编程错误而在宏扩展期间插入额外的空格。

【问题讨论】:

    标签: c macros c-preprocessor c99


    【解决方案1】:

    源代码在被 CPP 处理之前已经被标记化。

    所以你拥有的是一个/ 和一个* 令牌,它们不会隐式组合到/*“令牌”(因为 /* 并不是真正的预处理器令牌,所以我把它放在“”中)。

    如果使用 -E 输出预处理后的源 CPP 需要插入一个空格以避免 /* 被后续编译器通过。

    相同的功能可以防止两个例如来自不同宏的+ 符号在输出时组合成++ 标记。

    真正将两个预处理器标记粘贴在一起的唯一方法是使用## 运算符:

    #define P(x,y) x##y
    
    ...
    
    P(foo,bar)   
    

    生成令牌foobar

    P(+,+)
    

    导致令牌++,但是

    P(/,*)       
    

    无效,因为 /* 不是有效的预处理器令牌。

    【讨论】:

    • +1。我认为关键的见解是 -E 的输出确实没有由标准指定。该标准讨论了由一系列预处理标记组成的程序,然后将其转换为一系列标记。如何表示这些序列完全取决于预处理器,在这种情况下,如何将它们序列化为 bytes 序列的文件。当然,唯一可行的序列化是将作为等价的一系列预处理标记读回的序列化,因此正如您所说,它必须在两个标记之间放置空格,这两个标记一起形成一个。
    • 我同意 100%,想写一些类似你的解释的东西,但没有足够的时间。
    • 很好的答案,虽然我有两个挑剔的 cmets:没有 /* 令牌这样的东西; cmets 在标记化之前从源中删除。您可以使用 ## 从两个 + 令牌形成一个 ++ 令牌。
    • 是的,我提到 /* “令牌”是一种简化,更容易解释。并且确保您可以使用 ## 将两个部分连接到令牌中,但我说的是“隐式”连接,而不是使用 ## 进行显式粘合
    • 顺便说一句,如果您想尝试一下,您不能将 / 和 * 与 ## 一起粘贴,因为 ## 操作的结果必须是有效的预处理器令牌。正如您正确提到的那样 /* 不是预处理器令牌。
    【解决方案2】:

    预处理器的行为是标准化的。在http://en.wikipedia.org/wiki/C_preprocessor 的摘要中,您观察到的结果是:

    “3:标记化 - 预处理器将结果分解为预处理标记和空格。它将 cmets 替换为空格”。

    这发生在之前:

    “4:宏扩展和指令处理”。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-08-31
      • 1970-01-01
      • 2023-03-07
      • 2014-09-13
      • 1970-01-01
      • 1970-01-01
      • 2013-08-15
      • 1970-01-01
      相关资源
      最近更新 更多