对象式宏中单个哈希的影响

时间:2015-07-23 06:19:58

标签: c c-preprocessor language-lawyer

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

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,表示它允许#出现并且不执行任何特殊处理。但是,由于#运算符的定义在这种情况下没有定义行为,它实际上是未定义的行为吗?

1 个答案:

答案 0 :(得分:3)

正如您所注意到的,#仅在类似函数的宏中具有已定义的效果。 §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(例如{ {1}},§6.4.4.4/1)或u'c'(正是您所期望的,例如string-literal§6.4.5/ 1 )。

但是,它在§6.4.6/ 1 中列为L"String"。因此,允许在类似对象的宏的punctuator中进行逐字复制。它现在需要按照§6.10.3.4中的描述进行重新扫描。让我们看一下你的例子:

replacement-list将替换为C(A)C(X#Y)在这里没有特殊效果,因为它不在# replacement-list中,而在于CC(X#Y)显然已变为B(X#Y)。然后,通过B的{​​{1}}中的#运算符将B的参数转换为字符串文字,产生replacement-list

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