gpt4 book ai didi

c++ - 有效和无效的pp token 的定义是什么?

转载 作者:太空狗 更新时间:2023-10-29 20:38:29 34 4
gpt4 key购买 nike

我想广泛使用##-operator和enum魔术来处理大量类似的访问操作,错误处理和数据流。

如果应用###预处理程序运算符导致无效的pp token ,则该行为在C中未定义。

通常,在C90中未定义(*)预处理器操作的顺序(请参阅The token pasting operator)。现在,在某些情况下(在包括MISRA委员会在内的不同来源以及所引用的页面中这样说)中,多个## /#-运算符的顺序会影响未定义行为的发生。但是,我很难理解这些来源的示例并确定通用规则。

所以我的问题是:

  • 有效的pp token 有哪些规则?
  • 不同的C和C++标准之间是否有区别?
  • 我当前的问题:以下所有2个运算符(operator)命令是否合法?(**)
    #define test(A) test_## A ## _THING
    int test(0001) = 2;

  • 评论:

    (*)我不使用“是未定义的”,因为这与尚未定义的行为无关,恕我直言,而是未指定的行为。通常,使用多个##或#运算符不会使程序出错。显然有一个订单-我们只是无法预测哪个-因此该订单未指定。

    (**)这不是实际的编号申请。但是模式是等效的。

    最佳答案

    有效pp token 的规则是什么?

    这些在各自的标准中有详细说明; C11§6.4和C++ 11§2.4。在这两种情况下,它们都对应于生产预处理 token 。除了pp-number之外,它们也不足为奇。其余的可能性包括标识符(包括关键字),“标点符号”(在C++中,pre-processing-op-or-punc),字符串和字符文字,以及任何与任何其他乘积都不匹配的非空白字符。

    除少数异常(exception),任何字符序列都可以分解为有效的预处理 token 序列。 (一个异常(exception)是引号和撇号不匹配:单引号或撇号不是有效的预处理 token ,因此包含未终止字符串或字符文字的文本不能被标记化。)

    但是,在##运算符的上下文中,串联的结果必须是单个预处理 token 。因此,无效串联是一种串联,其结果是包含多个预处理 token 的字符序列。

    C和C++之间有区别吗?

    是的,有一些细微的差异:

  • C++具有用户定义的字符串和字符文字,并允许“原始”字符串文字。这些文字在C中的标记方式不同,因此它们可能是多个预处理标记,或者(对于原始字符串文字而言)甚至是无效的预处理标记。
  • C++包含符号::.*->*,所有这些符号在C中都将被标记为两个标点符号。此外,在C++中,一些看起来像关键字的东西(例如newdelete)是预处理操作的一部分-punc(尽管这些符号在两种语言中都是有效的预处理 token 。)
  • C允许使用十六进制浮点文字(例如1.1p-3),这在C++中不是有效的预处理 token 。
  • C++允许在整数文字中使用撇号作为分隔符(1'000'000'000)。在C语言中,这可能会导致不匹配的撇号。
  • 在通用字符名称(例如\u0234)的处理上存在细微差异。
  • 在C++中,除非后跟<::<,否则::将被标记为:>。 (通常使用最长匹配规则对<:::<::>进行标记。)在C语言中,最长匹配规则没有异常(exception); <::始终使用最长匹配规则进行 token 化,因此第一个 token 始终为<:

  • 即使未指定串联顺序,串联 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)

    无效 token 串联的示例有哪些?

    假设我们有
    #define concat3(a, b, c) a ## b ## c

    现在,无论串联顺序如何,以下内容均无效:
    concat3(., ., .)

    即使 .....也不是 token 。但是连接必须以某种顺序进行,并且 ..将是必要的中间值。由于这不是单个标记,因此串联将无效。
    concat3(27,e,-7)

    在这里, -7是两个标记,因此无法串联。

    在这种情况下,连接顺序很重要:
    concat3(27e, -, 7)

    如果将其从左到右串联,则将生成 27e- ## 7,它是两个pp-number的串联。但是 -不能与 7并置,因为 -7不是单个标记。

    pp数到底是什么?

    一般而言,pp-number是 token 的超集, token 可能会转换为(单个)数字文字或可能无效。该定义特意是宽泛的,部分是为了允许(某些) token 串联,另一部分是使预处理器与数值格式的定期更改隔离。可以在各自的标准中找到精确的定义,但非正式地,如果满足以下条件,则 token 是pp编号:
  • 它以一个十进制数字或一个句点(.)开头,后跟一个十进制数字。
  • token 的其余部分是字母,数字和句点,如果后面带有指数符号,则可能包括符号字符(+-)。两种语言的指数符号可以是Ee;从C99开始,还使用C语言编写了Pp
  • 在C++中,pp编号也可以包括(但不能以)撇号后跟字母或数字。
  • 注意:上面的letter包含下划线。同样,可以使用通用字符名称(C++中的撇号除外)。

  • 预处理终止后,如果可能,所有pp-numbers都将转换为数字文字。如果无法进行转换(因为 token 与任何数字文字的语法都不对应),则该程序无效。

    关于c++ - 有效和无效的pp token 的定义是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31320515/

    34 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com