C++;编译器开始考虑在字符串文字字符转义中使用两个以上的十六进制数字? 我在C++中有一个(生成的)文字字符串,它可能包含需要使用 \x/Cuth>符号进行转换的字符。例如: char foo[] = "\xABEcho";

C++;编译器开始考虑在字符串文字字符转义中使用两个以上的十六进制数字? 我在C++中有一个(生成的)文字字符串,它可能包含需要使用 \x/Cuth>符号进行转换的字符。例如: char foo[] = "\xABEcho";,c++,string,escaping,literals,C++,String,Escaping,Literals,但是,g++(版本4.1.2,如果有必要)会抛出一个错误: test.cpp:1: error: hex escape sequence out of range 编译器似乎将Ec字符视为前面十六进制数的一部分(因为它们看起来像十六进制数字)。由于四位十六进制数不适合字符,因此会引发错误。显然,对于宽字符串文本L“\xABEcho”而言,第一个字符将是U+ABEC,然后是L“ho” 在过去的几十年里,这种情况似乎有所改变,我从未注意到。我几乎可以肯定的是,旧的C编译器只考虑了 \x之后的两个十

但是,g++(版本4.1.2,如果有必要)会抛出一个错误:

test.cpp:1: error: hex escape sequence out of range
编译器似乎将
Ec
字符视为前面十六进制数的一部分(因为它们看起来像十六进制数字)。由于四位十六进制数不适合
字符
,因此会引发错误。显然,对于宽字符串文本
L“\xABEcho”
而言,第一个字符将是U+ABEC,然后是
L“ho”

在过去的几十年里,这种情况似乎有所改变,我从未注意到。我几乎可以肯定的是,旧的C编译器只考虑了<代码> \x<代码>之后的两个十六进制数字,并且不再进一步查看。 我可以想出一个解决方法:

char foo[] = "\xAB""Echo";
但这有点难看。所以我有三个问题:

  • 这是什么时候改变的

  • 为什么编译器不只接受宽字符串文本的>2位十六进制转义

  • 有没有比上述方法更简单的解决方法


  • 我非常肯定C++一直都是这样的。在任何情况下,
    字符位可能大于8,在这种情况下,
    '\xABE'
    '\xABEc'
    可能有效。

    GCC仅为:“每个[…]十六进制转义序列是可以构成转义序列的最长字符序列。”

    这些是宽字符文本

    char foo[] = "\x00ABEcho";
    
    可能更好

    这里有一些信息,不是gcc,但似乎仍然适用

    此链接包括重要的一行:

    在wchar\t字符串文本中指定
    \xnn
    等同于指定
    \x00nn

    这也可能有帮助


    我找到了我的问题的答案:

    • C++一直都是这样(查过Stroustrup第三版,之前没有)。K&R第一版根本没有提到
      \x
      (当时唯一可用的字符转义是八进制)。K&R第二版规定:

      其中hh是一个或多个十六进制数字(0…9,a…f,a…f)

      因此,这种行为似乎自ANSI C

    • 虽然编译器可能只接受大于2个字符的宽字符串文本,但这将不必要地使语法复杂化

    • 确实有一个不那么尴尬的解决办法:

      char foo[] = "\u00ABEcho";
      
      \u
      转义始终接受四个十六进制数字

    更新:并非所有情况下都可以使用
    \u
    ,因为(出于某种原因)不允许使用
    \u
    指定大多数ASCII字符。以下是GCC的一个片段:

    /* The standard permits $, @ and ` to be specified as UCNs.  We use
         hex escapes so that this also works with EBCDIC hosts.  */
      else if ((result < 0xa0
                && (result != 0x24 && result != 0x40 && result != 0x60))
               || (result & 0x80000000)
               || (result >= 0xD800 && result <= 0xDFFF))
        {
          cpp_error (pfile, CPP_DL_ERROR,
                     "%.*s is not a valid universal character",
                     (int) (str - base), base);
          result = 1;
        }
    
    /*该标准允许将$、@和`指定为UCS。我们使用
    十六进制转义,因此这也适用于EBCDIC主机*/
    否则如果((结果<0xa0
    &&(结果!=0x24&&result!=0x40&&result!=0x60))
    ||(结果:0x8000000)
    
    ||(result>=0xD800&&result我也通过使用\xnn指定以下字符来解决这个问题。不幸的是,只要[a..f]范围内有字符,就必须使用它。
    例如,“\xnneceg”被“\xnn\x65\x63\x65g”替换为“\xnn\x65\x63\x65g”

    我也遇到了这个问题。我发现我可以在第二个十六进制数字的末尾添加一个空格,然后通过在空格后面加上一个退格“\b”来消除空格。这不太理想,但似乎有效


    “尤利乌斯”C.Xe6SAR是FrANA \Xe7\BaIs的征服者“< /P>”只是猜测,但我可以看到至少有四个十六进制数字对于宽字符类型是有用的。@ JWW,你的解决方法已经被包括在这个问题中,被作者认为是丑陋的。C++参考文章总结了不同风格的规则。(十六进制、八进制等)非常好。根本不会改变这种行为,标准说“十六进制序列中的位数没有限制。”所以现在“\x00ABEc”被视为一个十六进制字符。@Ben Voigt:“在wchar\t字符串文字中指定
    \xnn
    相当于指定
    \x00nn
    ”。似乎有些编译器与您的解释不一致。但它对
    \xnnn
    有何说明?这被认为等同于
    \x00nn
    ?@Ignacio Vazquez Abrams:没什么。-1,请注意,这个答案不正确。只有十六进制转义序列是十六进制数字的最长序列。另一方面,八进制转义序列最多限制为三个八进制数字。这是标准规定的。(C++11,$2.14.3个字符的文字)@Wiz:你知道4.1.2有,对吧?@IgnacioVazquez Abrams我不知道你的意思。这条规则从C89的原始C标准开始就存在了。在C89/C99/C11/C++98/C++11中也是一样。我只是碰巧引用了最新的标准,仅此而已。@Wiz:那是否意味着该标准自相矛盾?我不是我不确定你的意思。标准只是说八进制转义序列最多可以是3个八进制数字,而十六进制转义序列的长度没有上限。此外,
    \u
    实际上并不等同于
    \x
    ,因为
    \x
    产生一个特定的整数值,而
    \u
    产生一个ce■ISO 10646编码点,因此数值取决于编码。在某些系统上,
    char
    可能需要三个或四个十六进制数字(甚至更多)。虽然
    char\u BIT
    通常为八个,但仍有一些系统(如数字信号处理器)在生产中,
    char
    是其他尺寸(16可能是除8以外最常见的大小)。有趣的是,转义中的十六进制数字的数量是无界的,但八进制数字的数量必须是1、2或3
    /* The standard permits $, @ and ` to be specified as UCNs.  We use
         hex escapes so that this also works with EBCDIC hosts.  */
      else if ((result < 0xa0
                && (result != 0x24 && result != 0x40 && result != 0x60))
               || (result & 0x80000000)
               || (result >= 0xD800 && result <= 0xDFFF))
        {
          cpp_error (pfile, CPP_DL_ERROR,
                     "%.*s is not a valid universal character",
                     (int) (str - base), base);
          result = 1;
        }