интервал х; scanf() с %d и printf() с %c

интервал х; Таким образом, для переменной будет 2 байта памяти. Теперь, если я ввел 66 и поскольку scanf() с %d, 66 будет храниться в 2-байтовой памяти, потому что переменная объявлена ​​как int.

Теперь в printf() с %c для отображения должны собираться данные только из памяти одного байта.

Но %c правильно отобразил B, получив правильные данные 66 из памяти для отображения.

Почему %c не может просто получить данные из одного байта?


person Javaid Akhtar    schedule 15.07.2017    source источник
comment
Предоставьте минимально воспроизводимый пример.   -  person Yunnosch    schedule 16.07.2017
comment
Обратите внимание, что int должен иметь ширину минимум 16 бит, но может быть и обычно бывает шире....   -  person ad absurdum    schedule 16.07.2017
comment
Дико предполагая, что ваш int неявно преобразуется в char, сохраняя значение 66, которое соответствует 8 битам char. Без MCVE быть более точным невозможно.   -  person Yunnosch    schedule 16.07.2017
comment
@Yunnosch - MCVE не требуется - это поведение четко определено.   -  person Oliver Charlesworth    schedule 16.07.2017
comment
это %c не просто получить данные из одного байта? --› он получает 2 (или 4) байта, а затем игнорирует все, кроме 1, для печати.   -  person chux - Reinstate Monica    schedule 16.07.2017
comment
Гм... Как вы решили, что %c получил свои данные из двух байтов? 66 — это число, которое идеально помещается всего в один байт. Возможно, ваш %c использовал этот один байт. Где доказательства использования двух байтов %c??? Без этого вопрос не имеет никакого смысла.   -  person AnT    schedule 16.07.2017
comment
Как %c может получить данные из двух или более байтов? Не ограничено ли получение данных из одного байта?   -  person Javaid Akhtar    schedule 16.07.2017


Ответы (3)


%c ожидает аргумент int из-за продвижения аргументов по умолчанию для функций с переменным аргументом. Другими словами, все нижеследующие в точности эквивалентны:

int x = 66;
char y = 66;
printf("%c", x);         // A
printf("%c", (char)x);   // B
printf("%c", y);         // C
printf("%c", (int)y);    // D

Итак, все, что происходит, это то, что printf интерпретирует значение int 66 как код ASCII1 и печатает соответствующий символ.


1. Обратите внимание, что ASCII технически является проектным решением, определяемым реализацией. Просто чрезвычайно распространенный.

person Oliver Charlesworth    schedule 15.07.2017

Спецификатор преобразования %c в операторе printf() ожидает аргумент int. Кроме того, поскольку printf() является функцией с переменным числом переменных, char преобразуется в int в силу аргумент продвижения по умолчанию.

Аргумент int, который передается в printf(), соответствующий спецификатору %c, имеет вид преобразован в unsigned char автором printf() перед печатью. Обратите внимание, что преобразование целочисленного типа signed в целочисленный тип unsigned выполняется четко определены в C и не предполагают сбор «данных только из одного байта». Скорее, если новый тип может содержать исходное значение, значение остается неизменным; в противном случае к старому (signed) значению (signed) добавляется (или вычитается) единица, превышающая максимальное значение для нового типа. Например, значение int -1 будет преобразовано в значение unsigned char (при условии, что UCHAR_MAX равно 255) -1 + 256 или 255, которое находится в пределах диапазона unsigned char.

Обратите внимание, что int со значением 66 не изменится при преобразовании в unsigned char, поскольку 66 находится в пределах диапазона unsigned char. UCHAR_MAX должно быть минимум из 255.

person ad absurdum    schedule 15.07.2017
comment
Где ОП упоминает, что он передает char printf? - person chqrlie; 16.07.2017
comment
@chqrlie-- Насколько я вижу, нигде; просто добавляя подробности о том, почему printf() ожидает int, но обычно передается char со спецификатором преобразования %c. - person ad absurdum; 16.07.2017
comment
Хорошая точка зрения. Чтобы добавить путаницы, 'a' на самом деле является int в C (в отличие от ++). - person chqrlie; 16.07.2017
comment
@chqrlie - это также хороший момент, что символьные константы имеют тип int для начала. Стоит ли удивляться, что этот материал немного сбивает с толку учащихся? - person ad absurdum; 16.07.2017
comment
«A» на самом деле является int в C, я это знаю. Это, я думаю, равно 65 и сохранено в памяти как соответствующая комбинация двоичных значений 8 0s и 1s как двоичный код. - person Javaid Akhtar; 16.07.2017

Независимо от того, как передается аргумент, спецификатор формата %c всегда преобразует свой аргумент в unsigned char перед его печатью. Итак, %c всегда печатает один байт.

Ваше утверждение, что %c получает данные из более чем одного байта, необоснованно. В представленном примере нет доказательств обратного — 66 — это число, умещающееся в один байт.

Сложности передачи аргументов с переменным числом аргументов (да, они передаются как int) не имеют никакого отношения к наблюдаемому поведению в этом случае.

person AnT    schedule 16.07.2017
comment
Я могу ошибаться, но кажется, что ОП считает, что %c ожидает char, и не понимает, что может произойти, когда фактический аргумент шире, чем char; отсюда моя попытка описать происходящее. Возможно, также запутался в представлении целочисленных типов.... - person ad absurdum; 16.07.2017
comment
Да сэр. Я смущен тем, что может произойти, когда фактический аргумент шире, чем размер символа, то есть один байт. Тогда куда в памяти должны идти данные больше одного байта? Потому что есть только один байт, который относится к переменной char. - person Javaid Akhtar; 16.07.2017
comment
Я знаю, что char на самом деле не что иное, как целое число - person Javaid Akhtar; 16.07.2017
comment
Но размер памяти двоичного кода char составляет всего один байт - person Javaid Akhtar; 16.07.2017