Лучшее понимание printf - Что печатается с "%c", когда предоставленное значение отрицательно?
В Kernighan & Ritchie говорится, что "все печатные символы положительны, когда тип данных char, подписанный или неподписанный, зависит от машины".
Может кто-нибудь объяснить мне значение этой строки? Моя система имеет подписанные символы, но даже с отрицательным значением, скажем, -90, printf печатает символ (хотя это не очень знакомый символ).
3 ответа
Набор символов ASCII определяет кодовые точки из 0x00
в 0x7F
, Неважно, представлены ли они байтовыми значениями без знака или со знаком, так как этот диапазон является общим для обоих.
Печатные символы находятся между 0x20
а также 0x7E
, которые являются частью ASCII. Термин печатный символ не определяет все возможные символы в мире, который можно печатать. Скорее это определяется внутри царства ASCII.
Байтовые значения из 0x80
в 0xFF
не определены в ASCII, и разные системы присваивают различные символы значениям в этом диапазоне, что приводит к множеству различных типов кодовых страниц, которые идентичны по своему диапазону ASCII, но различаются по этому диапазону. Это также диапазон, в котором значения для байтов со знаком и без знака различаются.
Реализация printf
ищет значение одного байта, когда он встречает %c
введите свой ввод. Это значение байта может быть подписано или не подписано относительно вашей точки зрения как вызывающей стороны printf
функция но printf
не знает этого. Он просто передает эти 8 бит в выходной поток, к которому он подключен, и этот поток испускает символы внутри 0x00
а также 0xff
,
Понятие знака не имеет смысла внутри конвейера вывода, где выбрасываются символы. Таким образом, отправляете ли вы 255
или -1
персонаж отображается 0xFF
в конкретной кодовой странице выбрасывается.
-90, поскольку подписанный символ повторно интерпретируется как неподписанный символ, в этом случае его значение равно 166. (Оба значения -90 и 166 равны 0xA6 в шестнадцатеричном формате.)
Вот так. Все двоичные числа положительны. Относитесь ли вы к этому негативно или нет - ваша собственная интерпретация. Используя комплимент общих двух.
8-битное число: 10100110 является положительным 166, что больше 128 (Максимальное 8-битное число с положительным знаком).
Используя знаковое арифметическое число 166 -90.
Вы видите персонажа, у которого значение ascii равно 166.
Используя это в качестве примера:
signed char x = -90;
printf("%c", x);
Целочисленные правила продвижения конвертируют x
в int
прежде чем передать его как аргумент printf
. (Обратите внимание, что ни один из других ответов не упоминает эту деталь, а некоторые подразумевают аргумент в пользуprintf
все еще является символом со знаком).
В разделе 7.21.6.1.6 стандарта (я использую стандарт C11) говорится о %c
символ флага:
Если модификатор длины l отсутствует, аргумент int преобразуется в беззнаковый char и записывается результирующий символ.
Итак, целое число -90
преобразуется в беззнаковый символ. Это означает (6.3.1.3.2):
... значение преобразуется путем многократного добавления или вычитания на единицу больше максимального значения, которое может быть представлено в новом типе, пока значение не окажется в диапазоне нового типа.
Если беззнаковый символ в вашей системе принимает значения от 0 до 255 (что почти наверняка так и есть), то результат будет -90 + 256 = 166. (Примечание: другие ответы относятся к "младшему байту" или "шестнадцатеричному представлению". предполагая представление дополнения до двух. Хотя это в подавляющем большинстве случаев встречается, стандарт C не гарантирует этого).
Затем символ 166 записывается в стандартный вывод и интерпретируется вашим терминалом.