Ответ 1
GCC только соответствует стандарту. # 877: "Каждая [...] шестнадцатеричная escape-последовательность - это самая длинная последовательность символов, которая может составлять escape-последовательность."
У меня есть (сгенерированная) литеральная строка на С++, которая может содержать символы, которые нужно экранировать с помощью нотации \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
и не будут выглядеть дальше.
Я могу подумать об одном обходном пути для этого:
char foo[] = "\xAB""Echo";
но это немного уродливо. Поэтому у меня есть три вопроса:
Когда это изменилось?
Почему компилятор не принимает > двухзначные шестнадцатеричные экраны для широкоформатных литералов?
Есть ли обходной путь, который менее неудобен, чем выше?
GCC только соответствует стандарту. # 877: "Каждая [...] шестнадцатеричная escape-последовательность - это самая длинная последовательность символов, которая может составлять escape-последовательность."
Я нашел ответы на свои вопросы:
С++ всегда был таким образом (проверено третье издание Stroustrup, ранее не было). В первом выпуске K & R не упоминалось \x
вообще (единственный доступ к символу, доступный в то время, был восьмеричным). K & R 2nd edition гласит:
'\xhh'
где hh - одна или несколько шестнадцатеричных цифр (0... 9, a... f, A... F).
поэтому, похоже, это поведение было связано с ANSI C.
Хотя возможно, что компилятор может принимать только 2 символа для широкоформатных литералов, это излишне усложняло бы грамматику.
В действительности существует менее сложное обходное решение:
char foo[] = "\u00ABEcho";
Вывод \u
всегда принимает четыре шестнадцатеричных цифры.
Обновить. Использование \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;
}
Я решил это, указав следующий char с \xnn тоже. К сожалению, вы должны использовать это до тех пор, пока в диапазоне [a..f] есть char. ех. "\ xnneceg" заменяется на "\ xnn\x65\x63\x65g"
Я уверен, что С++ всегда был таким. В любом случае CHAR_BIT
может быть больше 8, и в этом случае '\xABE'
или '\xABEc'
могут быть действительными.
Я также столкнулся с этой проблемой. Я обнаружил, что я мог бы добавить пробел в конце второй шестнадцатеричной цифры, а затем избавиться от пространства, следуя пробелу с пространством "\ b". Не совсем желательно, но, похоже, это работает.
"Юлий C\xE6sar завоеватель frana\xE7\bais"
Это широкоформатные литералы.
char foo[] = "\x00ABEcho";
Может быть, лучше.
Здесь некоторая информация, а не gcc, но все же кажется применимой.
Эта ссылка содержит важную строку:
Задание
\xnn
в строковом литерале wchar_t эквивалентно заданию\x00nn
Это также может быть полезно.
http://www.gnu.org/s/hello/manual/libc/Extended-Char-Intro.html#Extended-Char-Intro