Что стандарт C указывает для значения символьной константы с шестнадцатеричной escape-последовательностью? - PullRequest
3 голосов
/ 07 июня 2019

Что стандарт C 2018 указывает для значения шестнадцатеричной escape-последовательности, такой как '\xFF'?

Рассмотрим реализацию C, в которой char имеет подпись и восемь битов.

В п. 6.4.4.4 говорится о символьных константах.В пункте 6 обсуждаются шестнадцатеричные escape-последовательности:

Шестнадцатеричные цифры, которые следуют за обратной косой чертой, и буква x в шестнадцатеричной escape-последовательности считаются частью конструкцииодин символ для константы целого символа или один широкий символ для константы широкого символа.Числовое значение шестнадцатеричного целого числа, сформированного таким образом, указывает значение требуемого символа или широкого символа.

Шестнадцатеричное целое число - «FF».По обычным правилам шестнадцатеричной записи его значение 1 равно 255. Обратите внимание, что пока у нас нет определенного типа: «символ» является «членом набора элементов, используемых дляорганизация, управление или представление данных »(3.7) или« битовое представление, которое помещается в байт »(3.7.1).Когда \xFF используется в '\xFF', в грамматике это c-char (6.4.4.4 1), а '\xFF' - целочисленная символьная константа.Согласно 6.4.4.4 2, «Целочисленная символьная константа - это последовательность из одного или нескольких многобайтовых символов, заключенных в одинарные кавычки, как в 'x'

6.4.4.4 9 определяетограничения на символьные константы:

Значение восьмеричной или шестнадцатеричной escape-последовательности должно находиться в диапазоне представимых значений для соответствующего типа:

, за которым следуеттаблица, которая для символьных констант без префикса показывает соответствующий тип: unsigned char.

Пока все хорошо.Наша шестнадцатеричная escape-последовательность имеет значение 255, которое находится в диапазоне unsigned char.

Тогда 6.4.4.4 10 имеет намерение сообщить нам значение символьной константы.Я цитирую его здесь с разделенными предложениями и помеченными для справки:

(i) Целочисленная символьная константа имеет тип int .

(ii) Значениецелочисленной символьной константы, содержащей один символ, который отображается на однобайтовый исполнительный символ, является числовое значение представления сопоставленного символа, интерпретируемое как целое число.

(iii) Значение целочисленной символьной константысодержащий более одного символа (например, 'ab' ) или содержащий символ или escape-последовательность, которая не отображается на однобайтовый символ выполнения, определяется реализацией.

(iv) Если целочисленная символьная константа содержит один символ или escape-последовательность, ее значение является значением, которое получается, когда объект с типом char , значение которого равно значению одиночного символа или escape-последовательности, преобразуется в тип int .

Если 255 соответствует исполняемому символу, применяется (ii) и значение '\xFF' является значением этого символа.Это первое использование «карт» в стандарте;это не определено в другом месте.Должно ли это означать что-либо, кроме сопоставления значения, полученного до сих пор (255), с исполняющим символом с тем же значением?Если это так, для применения (ii) должен существовать исполнительный символ со значением 255. Тогда значение '\xFF' будет равно 255.

В противном случае (iii) применяется и значение '\xFF' определяется реализацией.

Независимо от того, применяется ли (ii) или (iii), также применяется (iv).Он говорит, что значение '\xFF' является значением char объекта, значение которого равно 255, впоследствии преобразованного в int.Но, поскольку char является знаковым и восьмибитным, нет объекта char, значение которого равно 255. Поэтому в четвертом предложении говорится о невозможности.

Сноска

1 3,19 определяет«Значение» как «точное значение содержимого объекта при интерпретации как имеющего определенный тип», но я не верю, что здесь используется технический термин.«Числовое значение шестнадцатеричного целого числа» пока не обсуждается.Похоже, это употребление слова «ценность» в обычном смысле.

1 Ответ

1 голос
/ 07 июня 2019

Ваша демонстрация приводит к интересному выводу:

Не существует переносимого способа записи символьных констант со значениями вне диапазона 0 .. CHAR_MAX.Это не обязательно проблема для отдельных символов, поскольку вместо символьных констант можно использовать целые числа, но такой альтернативы для строковых констант не существует.

Кажется, что тип char всегда должен быть беззнаковымпо умолчанию для согласованности со многими стандартными библиотечными функциями C:

  • fgetc() возвращает int с отрицательным значением EOF для сбоя, а значение unsigned char является байтомбыл успешно прочитан.Следовательно, значение и эффект fgetc() == '\xFF' определяются реализацией.

  • функции из <ctype.h> принимают аргумент int с теми же значениями, которые возвращаются fgetc().Передача отрицательного значения char имеет неопределенное поведение.

  • strcmp() и сравнивает строки на основе значений символов, преобразованных в unsigned char.

  • '\xFF' может иметь значение -1, которое совершенно неинтуитивно и потенциально идентично значению EOF.

Единственная причина, чтобы создать или сохранить char подписано по умолчанию - это совместимость со старыми компиляторами для исторического кода, который основан на этом поведении и был написан до появления signed char, около 30 лет назад!

Я настоятельно советую программистам использовать -funsigned-char дляchar по умолчанию без знака и использует signed char или лучше int8_t, если требуется 8-битные переменные со знаком и члены структуры.

Как прокомментировал hyde , чтобы избежать проблем с переносимостью, char значения должны быть приведены как (unsigned char), где подпись char может вызвать проблемы: например:

    char str[] = "Hello world\n";
    for (int i = 0; str[i]; i++)
        str[i] = tolower((unsigned char)str[i]);
...