【问题标题】:Effect of single hash in object-like macro类对象宏中单个哈希的影响
【发布时间】:2015-07-23 06:19:57
【问题描述】:

在类对象宏中是否允许#,如果允许,会发生什么?

C 标准仅在类函数宏的宏中定义# 的行为。

示例代码:

#include <stdio.h>

#define A X#Y
#define B(X) #X
#define C(X) B(X)

int main()
{
    printf(C(A) "\n");
}

gcc 输出X#Y,表明它允许# 存在并且不执行特殊处理。但是,由于#运算符的定义并没有定义这种情况下的行为,它实际上是未定义的行为吗?

【问题讨论】:

    标签: c c-preprocessor language-lawyer


    【解决方案1】:

    正如您所注意到的,# 仅在类似函数的宏中具有定义的效果。 § 6.10.3.2/1(所有对标准的引用均来自 C11 草案 (N1570))。要了解在类对象宏中发生了什么,我们必须看看别处。

    表单的预处理指令

    # define identifier replacement-list new-line
    

    定义一个 类对象宏 这会导致宏名称的每个后续实例 由构成 指令的其余部分。 [...]

    § 6.10.3/9

    因此,唯一的问题是# 是否允许在replacement-list 中。如果是,则照常参与替换。

    我们在 § 6.10/1 中找到语法:

    replacement-list:
        pp-tokens (opt.)
    
    pp-tokens:
        preprocessing-token
        pp-tokens preprocessing-token
    

    现在,# 是有效的preprocessing-token 吗? § 6.4/1 说:

    preprocessing-token:
        header-name
        identifier
        pp-number
        character-constant
        string-literal
        punctuator
        each non-white-space character that cannot be one of the above
    

    这当然不是header-name§ 6.4.7/1),identifier 令牌中不允许使用它(§ 6.4.2.1/1),也不是pp-number(基本上是允许格式的任何数字,§ 6.4.8/1),也不是character-constant(例如u'c'§ 6.4 .4.4/1)或string-literal(正是您所期望的,例如L"String"§ 6.4.5/1)。

    但是,它在 § 6.4.6/1 中被列为 punctuator。因此,它在类对象宏的replacement-list 中是允许的,并且将被逐字复制。它现在需要重新扫描,如 § 6.10.3.4 中所述。让我们看看你的例子:

    C(A) 将替换为 C(X#Y)#这里没有特殊作用,因为它不在Creplacement-list中,而是在它的参数中。 C(X#Y) 显然变成了B(X#Y)。然后B 的参数通过Breplacement-list 中的# 运算符转换为字符串文字,产生"X#Y"

    因此,您没有未定义的行为。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-11-20
      • 1970-01-01
      • 2012-05-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-06
      • 2018-01-23
      相关资源
      最近更新 更多