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

问题描述 投票:0回答:7

我在 C++ 中有一个(生成的)文字字符串,其中可能包含需要使用

\x
表示法转义的字符。例如:

char foo[] = "\xABEcho";

但是,g++(版本 4.1.2,如果重要的话)会抛出错误:

test.cpp:1: error: hex escape sequence out of range

编译器似乎将

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

这似乎在过去几十年里发生了变化,但我从未注意到。我几乎可以肯定,旧的 C 编译器只会考虑 \x 之后的

two
十六进制数字,而不会再进一步查看。

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

char foo[] = "\xAB""Echo";

但这有点难看。所以我有三个问题:

  • 什么时候改变的?

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

  • 有没有比上面的方法不那么尴尬的解决方法?

c++ string escaping literals
7个回答
30
投票

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


23
投票

我找到了问题的答案:

  • C++ 一直都是这样(查看了 Stroustrup 第三版,之前没有)。 K&R 第一版根本没有提到

    \x
    (当时唯一可用的字符转义是八进制)。 K&R 第二版指出:

    '\xhh'
    

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

    看来这种行为自 ANSI C 以来就已经存在了。

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

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

    char foo[] = "\u00ABEcho";
    

    \u
    转义始终接受four十六进制数字。

更新

\u
的使用并不完全适用于所有情况,因为大多数 ASCII 字符(由于某种原因)不允许使用
\u
指定。这是 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;
    }

5
投票

我很确定 C++ 一直都是这样。在任何情况下,

CHAR_BIT
都可能大于 8,在这种情况下
'\xABE'
'\xABEc'
可能是有效的。


5
投票

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


0
投票

如果您的编译器支持内联字符串文字连接,则以下操作有效:

char foo[] = "\xAB""Echo";

-1
投票

这些是宽字符文字。

char foo[] = "\x00ABEcho";

可能会更好。

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

http://publib.boulder.ibm.com/infocenter/iadthelp/v7r0/index.jsp?topic=/com.ibm.etools.iseries.pgmgd.doc/cpprog624.htm

此链接包含重要的一行:

在 wchar_t 字符串文字中指定

\xnn
相当于指定
\x00nn

这也可能有帮助。

http://www.gnu.org/s/hello/manual/libc/Extended-Char-Intro.html#Extended-Char-Intro


-2
投票

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

“弗拉纳征服者朱利叶斯·C\xE6sar\xE7 ais”

© www.soinside.com 2019 - 2024. All rights reserved.