Когда компиляторы C ++ начали рассматривать более двух шестнадцатеричных цифр в экранированных строковых литералах? - PullRequest
54 голосов
/ 26 апреля 2011

У меня есть (сгенерированная) литеральная строка в 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 и не будут смотреть дальше.

Я могу придумать один обходной путь для этого:

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

но это немного некрасиво. Итак, у меня есть три вопроса:

  • Когда это изменилось?

  • Почему компилятор не принимает> двухзначные шестнадцатеричные экранирования для широких строковых литералов?

  • Есть ли обходной путь, который менее неудобен, чем описанный выше?

Ответы [ 6 ]

26 голосов
/ 26 апреля 2011

GCC только в соответствии со стандартом . # 877 : "Каждая шестнадцатеричная escape-последовательность [...] является самой длинной последовательностью символов, которая может составлять escape-последовательность."

21 голосов
/ 26 апреля 2011

Я нашел ответы на свои вопросы:

  • C ++ всегда был таким (проверял Stroustrup 3-е издание, раньше не было).1-е издание K & R вообще не упоминало \x (единственные экранированные символы, доступные в то время, были восьмеричными).2-е издание K & R гласит:

    '\xhh'
    

    , где чч - это одна или несколько шестнадцатеричных цифр (0 ... 9, a ... f, A ... F).

    , поэтому кажется, что такое поведение существовало со времени ANSI C.

  • Хотя компилятор может принимать только> 2 символа для широкогостроковые литералы, это излишне усложнит грамматику.

  • Существует действительно менее неудобный обходной путь:

    char foo[] = "\u00ABEcho";
    

    \u escape принимает 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;
    }
4 голосов
/ 03 апреля 2016

Я решил это, указав следующий символ с \ xnn. К сожалению, вы должны использовать это до тех пор, пока в диапазоне [a..f] есть char. ех. «\ xnneceg» заменяется на «\ xnn \ x65 \ x63 \ x65g»

3 голосов
/ 26 апреля 2011

Я почти уверен, что C ++ всегда был таким.В любом случае CHAR_BIT может быть больше 8, в этом случае '\xABE' или '\xABEc' могут быть действительными.

0 голосов
/ 16 октября 2017

Я тоже столкнулся с этой проблемой.Я обнаружил, что могу добавить пробел в конце второй шестнадцатеричной цифры, а затем избавиться от пробела, следуя пробелу с помощью пробела «\ b».Не совсем желательно, но, похоже, это сработало.

"Юлий С \ xE6sar, победитель франки \ xE7 \ bais"

0 голосов
/ 26 апреля 2011

Это литералы широких символов.

char foo[] = "\x00ABEcho";

Может быть, лучше.

Вот некоторая информация, не gcc, но, кажется, все еще применима.

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

Эта ссылка содержит важную строку:

Указание \xnn в строковом литерале wchar_t эквивалентно указанию \x00nn

Это также может быть полезно.

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

...