什么时候C++编译器开始考虑字符串文字字符转义中的两个以上十六进制数字?

Gre*_*ill 55 c++ string escaping literals

我在C++中有一个(生成的)文字字符串,可能包含需要使用\x表示法转义的字符.例如:

char foo[] = "\xABEcho";
Run Code Online (Sandbox Code Playgroud)

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

test.cpp:1: error: hex escape sequence out of range
Run Code Online (Sandbox Code Playgroud)

编译器似乎将Ec字符视为前一个十六进制数字的一部分(因为它们看起来像十六进制数字).由于四位十六进制数不适合a char,因此会引发错误.显然,对于宽字符串文字L"\xABEcho",第一个字符是U + ABEC,其次是L"ho".

在过去的几十年里,这似乎发生了变化,我从未注意到.我几乎可以肯定旧的C编译器只会考虑两个十六进制数字\x,而不再看了.

我可以想到一个解决方法:

char foo[] = "\xAB""Echo";
Run Code Online (Sandbox Code Playgroud)

但那有点难看.所以我有三个问题:

  • 这什么时候改变了?

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

  • 有没有比上述更难的解决方法?

Ign*_*ams 26

GCC仅遵循该标准.#877:"每个[...]十六进制转义序列是可以构成转义序列的最长字符序列."


Gre*_*ill 21

我找到了问题的答案:

  • C++一直都是这样(检查过Stroustrup第3版,之前没有任何内容).K&R第1版完全没有提及\x(当时唯一可用的角色是八进制).K&R第2版声明:

    '\xhh'
    
    Run Code Online (Sandbox Code Playgroud)

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

    所以看起来这种行为自ANSI C以来就存在.

  • 虽然编译器可能只接受> 2个字符作为宽字符串文字,但这会不必要地使语法复杂化.

  • 确实有一个不太尴尬的解决方法:

    char foo[] = "\u00ABEcho";
    
    Run Code Online (Sandbox Code Playgroud)

    \u逃生接受4个十六进制数字始终.

更新:使用\u并不适用于所有情况,因为大多数ASCII字符(由于某种原因)不允许使用\u.以下是海湾合作委员会的一个片段:

/* 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;
    }
Run Code Online (Sandbox Code Playgroud)

  • `\ u`在'\ x`产生特定整数值的意义上也不等同于`\ x`,而`\ u`产生一定的ISO 10646代码点,因此数值取决于编码. (4认同)

Ben*_*igt 5

我很确定 C++ 一直都是这样。在任何情况下,都CHAR_BIT可能大于 8,在这种情况下'\xABE'还是'\xABEc'可能有效。


小智 5

我也通过用 \xnn 指定以下字符来解决这个问题。不幸的是,只要 [a..f] 范围内有 char,您就必须使用它。前任。“\xnneceg”被替换为“\xnn\x65\x63\x65g”