Mar*_* A. 3 c c++ c89 c-preprocessor
我想广泛使用## - 运算符和枚举魔法来处理大量类似的访问操作,错误处理和数据流.
如果应用##和#预处理器运算符导致无效的pp-token,则行为在C中未定义.
一般情况下,预处理器操作的顺序未在C90中定义(*)(请参阅令牌粘贴操作符).现在在某些情况下,它发生(在不同来源,包括MISRA委员会,以及引用的页面),多个## /# - 运算符的顺序会影响未定义行为的发生.但是我很难理解这些来源的例子并确定共同规则.
所以我的问题是:
有效pp-tokens有哪些规则?
不同的C和C++标准之间有区别吗?
我目前的问题:以下所有2个操作员订单是否合法?(**)
#define test(A) test_## A ## _THING
int test(0001) = 2;
Run Code Online (Sandbox Code Playgroud)评论:
(*)我不使用"未定义",因为这与未定义的行为有关,但恕我直言,而是未指定的行为.应用了多个##或#运算符通常不会使程序错误.显然有一个订单 - 我们无法预测哪个 - 所以订单是未指定的.
(**)这不是编号的实际应用.但模式是等价的.
这些都在各自的标准中阐明; C11§6.4和C++11§2.4.在这两种情况下,它们都对应于生产预处理令牌.除了pp-number,它们也不应该太令人惊讶.剩下的可能性是标识符(包括关键字),"标点符号"(在C++中,预处理-op-or-punc),字符串和字符文字,以及任何与其他任何产品都不匹配的单个非空白字符.
除了少数例外,任何字符序列都可以分解为一系列有效的预处理标记.(一个例外是无法匹配的引号和撇号:单引号或撇号不是有效的预处理标记,因此包含未终止的字符串或字符文字的文本无法标记化.)
##但是,在运算符的上下文中,连接的结果必须是单个预处理标记.因此无效的连接是连接,其结果是包含多个预处理标记的字符序列.
是的,有一点点差异:
C++具有用户定义的字符串和字符文字,并允许"原始"字符串文字.这些文字将在C中以不同方式标记,因此它们可能是多个预处理标记或(在原始字符串文字的情况下)甚至是无效的预处理标记.
C++包含符号::,.*并且->*所有这些都将被标记为C中的两个标点符号.此外,在C++中,一些看起来像关键字的东西(例如new,delete)是预处理的一部分- op-or-punc(尽管这些符号是两种语言中有效的preprocssing-tokens.)
C允许十六进制浮点文字(例如1.1p-3),它们在C++ 中不是有效的预处理标记.
C++允许将撇号在整数文字中用作分隔符(1'000'000'000).在C中,这可能会导致无法匹配的撇号.
通用字符名称的处理方式略有不同(例如\u0234).
在C++中,<::将被标记为<,::除非它后跟:或>.(<:::并<::>使用最长匹配规则正常标记.)在C中,最长匹配规则没有例外; <::始终使用最长匹配规则进行标记,因此第一个标记将始终是<:.
test_,0001并且_THING,即使连接顺序未指定?是的,这两种语言都是合法的.
test_ ## 0001 => test_0001 (identifier)
test_0001 ## _THING => test_0001_THING (identifier)
0001 ## _THING => 0001_THING (pp-number)
test_ ## 0001_THING => test_0001_THING (identifier)
Run Code Online (Sandbox Code Playgroud)
假设我们有
#define concat3(a, b, c) a ## b ## c
Run Code Online (Sandbox Code Playgroud)
现在,无论串联顺序如何,以下都是无效的:
concat3(., ., .)
Run Code Online (Sandbox Code Playgroud)
..即使是,也不是令牌....但是,连接必须按某种顺序进行,并且..是必要的中间值; 由于这不是单个令牌,因此连接将无效.
concat3(27,e,-7)
Run Code Online (Sandbox Code Playgroud)
这里-7是两个令牌,所以它不能连接.
这是一个连接顺序很重要的情况:
concat3(27e, -, 7)
Run Code Online (Sandbox Code Playgroud)
如果这是从左到右连接的,则会产生27e- ## 7,这是两个pp数的串联.但-不能连接7,因为(如上所述)-7不是单一的令牌.
一般而言,pp-number是令牌的超集,可能会转换为(单个)数字文字或可能无效.该定义有意宽泛,部分是为了允许(某些)令牌连接,部分是为了使预处理器与数字格式的周期性变化隔离.精确定义可以在相应的标准中找到,但非正式地,如果出现以下情况,则令牌是pp编号:
.)后跟十进制数字开头.+,-).该指数符号可以是E或e两种语言; 并且还P与p在C,因为C C99.letter包括下划线.此外,可以使用通用字符名称(除了在C++中使用撇号之外).一旦预处理终止,所有pp-number将尽可能转换为数字文字.如果无法进行转换(因为令牌与任何数字文字的语法不对应),则程序无效.