Как правильно добавить шестнадцатеричные переходы в строковый литерал?

Когда у вас есть строка в C, вы можете добавить прямой шестнадцатеричный код внутри.

char str[] = "abcde"; // 'a', 'b', 'c', 'd', 'e', 0x00
char str2[] = "abc\x12\x34"; // 'a', 'b', 'c', 0x12, 0x34, 0x00

Оба примера имеют 6 байтов в памяти. Теперь проблема существует, если вы хотите добавить значение [a-fA-F0-9] после шестнадцатеричной записи.

//I want: 'a', 'b', 'c', 0x12, 'e', 0x00
//Error, hex is too big because last e is treated as part of hex thus becoming 0x12e
char problem[] = "abc\x12e";

Возможное решение - заменить после определения.

//This will work, bad idea
char solution[6] = "abcde";
solution[3] = 0x12;

Это может сработать, но не получится, если вы поставите его как const,

//This will not work
const char solution[6] = "abcde";
solution[3] = 0x12; //Compilation error!

Как правильно вставить e после \x12 без ошибки запуска?


Почему я спрашиваю? Если вы хотите построить строку UTF-8 как константу, вы должны использовать шестнадцатеричные значения символов, если она больше, чем может содержать таблица ASCII.

3 ответа

Решение

Используйте 3 восьмеричные цифры:

char problem[] = "abc\022e";

или разделить вашу строку:

char problem[] = "abc\x12" "e";

Почему это работает:

  • В отличие от шестнадцатеричных кодировок, стандарт определяет 3 цифры как максимальную сумму для восьмеричного экранирования.

    6.4.4.4 Символьные константы

    ...

    octal-escape-sequence:
        \ octal-digit
        \ octal-digit octal-digit
        \ octal-digit octal-digit octal-digit
    

    ...

    hexadecimal-escape-sequence:
        \x hexadecimal-digit
        hexadecimal-escape-sequence hexadecimal-digit
    
  • Строковая конкатенация букв определяется как более поздняя фаза перевода, чем преобразование литеральных escape-символов.

    5.1.1.2 Этапы перевода

    ...

    1. Каждый элемент исходного набора символов и escape-последовательность в символьных константах и ​​строковых литералах преобразуются в соответствующий элемент набора символов выполнения; если соответствующего члена нет, он преобразуется в определяемый реализацией член, отличный от нулевого (широкого) символа. 8)

    2. Литеральные токены соседних строк объединяются.

Поскольку строковые литералы конкатенируются на ранних этапах процесса компиляции, но после преобразования экранированных символов вы можете просто использовать:

char problem[] = "abc\x12" "e";

хотя вы можете предпочесть полное разделение для удобства чтения:

char problem[] = "abc" "\x12" "e";

Для языковых юристов среди нас это рассматривается в C11 5.1.1.2 Translation phases (мой акцент):

  1. Каждый элемент исходного набора символов и escape-последовательность в символьных константах и строковых литералах преобразуются в соответствующий элемент набора символов выполнения; если соответствующего члена нет, он преобразуется в определяемый реализацией член, отличный от нулевого (широкого) символа.

  2. Литеральные токены соседних строк объединяются.

Почему я спрашиваю? Когда вы хотите построить строку UTF-8 как константу, вы должны использовать шестнадцатеричные значения символов больше, чем может содержать таблица ASCII.

Ну нет. Вам не нужно. Начиная с C11, вы можете использовать префикс вашей строковой константы с помощью u8, который сообщает компилятору, что символьный литерал находится в UTF-8.

char solution[] = u8"no need to use hex-codes á駵";

(Кстати, то же самое поддерживается и в C++11)

Другие вопросы по тегам