При объяснении такого поведения необходимо учитывать следующие моменты:
Во-первых, в таком задании, как c=i
в
int i=1000;
char c='A';
c=i;
, мы должны учитывать, что i
является перед назначением преобразован в тип c
. Интегральное преобразование определяется здесь в онлайн-проекте стандарта C99:
6.3.1.3 Целые числа со знаком и без знака
1 Когда значение с целочисленным типом преобразуется в другой целочисленный тип, отличный от _Bool, если значение может быть представлено новым типом, оно не изменяется.
2 В противном случае, если новый тип беззнаковый, значение преобразуется многократно добавление или вычитание на единицу большего, чем максимальное значение, которое может быть представлено в новом типе до тех пор, пока значение не окажется в диапазоне нового типа. 60)
3 В противном случае новый тип подписывается и ценность не может быть представлена в нем; либо результат определяется реализацией, либо возникает сигнал, определяемый реализацией.
Таким образом, необходимо знать, является ли char
индивидуальным целочисленным типом или нет. Это может отличаться от компилятора к компилятору, но кажется, что ваш компилятор считает тип char
как signed char
по умолчанию.
В случае signed char
, «результат определяется реализацией», и нам нужно будет взглянуть на спецификацию компилятора.
Общая реализация состоит в том, что целое значение 1000, которое в двоичном формате равно 00000011 11101000
, усекается до 8 бит и сохраняется в значении char.
Что означает 11101000
для signed char
определяется в представлении типов :
6-2-6-2 Целочисленные типы
2 Для целого числа со знаком типов, биты представления объекта должны быть разделены на три группы: биты значения, биты заполнения и бит знака. Никаких дополнительных битов быть не должно; знаковый char не должен иметь битов заполнения. Должен быть ровно один знаковый бит. Каждый бит, который является битом значения, должен иметь то же значение, что и тот же бит в объектном представлении соответствующего беззнакового типа (если есть M битов значений в типе со знаком и N в типе без знака, тогда M <= N). Если знаковый бит равен нулю, он не влияет на результирующее значение. Если знаковый бит равен единице, значение должно быть изменено одним из следующих способов: </p>
соответствующее значение со знаковым битом 0 инвертируется (знак и величина);
знаковый бит имеет значение - (2M) (дополнение до двух);
знаковый бит имеет значение - (2M - 1) (дополнение до единиц).
Что из этого применимо, определяется реализацией, как ...
Опять же, результат определяется в реализацией компилятора; но обычная интерпретация - это дополнение до двух, интерпретирующее наиболее значимый бит как знаковый бит:
В вашем случае 8 битов 11101000
- это один знаковый бит (установленный) и 7 битов остатка; остаток равен 1101000
, что составляет 104; тогда фактическое значение в дополнении до двух будет - (127-104 + 1), что равно -24.
Обратите внимание, что неясно, будет ли результат -24; другие компиляторы могут дать другие результаты.
Есть даже еще один шаг, который необходимо рассмотреть, поскольку вы печатаете значение символа со знаком с использованием спецификатора формата "% d": отрицательное значение signed char
повышается до типа int
; но тогда это даст "то же самое" отрицательное значение. Я опускаю объяснение «продвижения» и почему аргументы в printf
вообще продвигаются.