我在 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++ 一直都是这样(查看了 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;
}
我很确定 C++ 一直都是这样。在任何情况下,
CHAR_BIT
都可能大于 8,在这种情况下 '\xABE'
或 '\xABEc'
可能是有效的。
我也通过用 \xnn 指定以下字符来解决这个问题。不幸的是,只要 [a..f] 范围内有 char,您就必须使用它。 前任。 “\xnneceg”被替换为“\xnn\x65\x63\x65g”
如果您的编译器支持内联字符串文字连接,则以下操作有效:
char foo[] = "\xAB""Echo";
这些是宽字符文字。
char foo[] = "\x00ABEcho";
可能会更好。
这里有一些信息,不是 gcc,但似乎仍然适用。
此链接包含重要的一行:
在 wchar_t 字符串文字中指定
相当于指定\xnn
\x00nn
这也可能有帮助。
http://www.gnu.org/s/hello/manual/libc/Extended-Char-Intro.html#Extended-Char-Intro
我也遇到了这个问题。我发现我可以在第二个十六进制数字的末尾添加一个空格,然后通过在空格后面加上退格键“”来删除该空格。不太理想,但似乎有效。
“弗拉纳征服者朱利叶斯·C\xE6sar\xE7 ais”