将引号符号传递给宏

时间:2017-05-20 17:06:56

标签: c++ preprocessor

Image

如何将只带一个引号的参数传递给宏?

2 个答案:

答案 0 :(得分:3)

你不能这样做。

预处理器对语法的要求比编译器要少得多,但是你提供的内容仍然必须是一系列有效的令牌,而未终止的字符串文字不是有效的令牌。

答案 1 :(得分:1)

如果您的系统使用ASCII / ISO 8859-k作为其单字节编码 - 这不是完全可移植的,但例外现在非常罕见 - 那么您可以写:

std::cout << DEF(\x22qwer) << std::endl;

注意显然相似

std::cout << DEF(\u0022qwer) << std::endl;

不起作用。为了理解为什么不这样做,理解第一个工作的原因(或如何工作)很重要,因为机制并不像它看起来那么明显。

编译器的输入必须包含一系列标记和空格,而DEF函数的参数也不例外。当编译器最初对包含DEF函数的行进行标记时,它不知道它的参数将被字符串化,因此该参数必须可分解为标记。

幸运的是,预处理器在它认为是令牌时非常自由。对于C ++,可能的预处理器标记是:(§2.4[lex.pptoken])

header-name
identifier
pp-number
character-literal
user-defined-character-literal
string-literal
user-defined-string-literal
preprocessing-op-or-punc
each non-white-space character that cannot be one of the above

\x22qwer不符合上述任何条件,但\是非空格字符,不能是其他令牌之一,x22qwer是{{1} }}。因此identifier的参数包含两个令牌而没有插入空格,stringify运算符尽职尽责地将其转换为字符串文字,然后根据字符串文字规则重新解释,其中连续字符DEF是替换为双引号(或执行字符编码中对应于0x22的任何字符)。

另一方面,\x22不起作用。原因是DEF(\u0022qwer)通用字符名称,因此\u0022满足标识符的词法生成。这使它成为一个单一的标记。但它不是有效的标识符标记,因为\u0022qwer不在有效标识符字符的通用字符列表中(根据§2.10[lex.name]表2)。

如果你已经浏览了stringify运算符的详细描述,那么你可能会惊讶于stringify操作不会改变反斜杠。需要仔细阅读。 §16.3.2[cpp.stringize]:

  

参数中每个预处理标记的原始拼写都保留在字符串文字中,除了用于生成字符串文字和字符文字拼写的特殊处理:在每个拼写之前插入一个 \ 字符 \ 字符文字或字符串文字的字符(包括分隔字符)。

那里有一个重要的资格:只有引号和反斜杠是字符或字符串文字的一部分才会被重新转义。 \u0022中的反斜杠不是字符或字符串文字的一部分,因此它将保持不变。