Повтор соответствующей части кода из вопроса:
unsigned int a = 10;
signed int b = -5;
printf("%d\n", a + b); /* 5 */
printf("%u\n", a + b); /* 5 */
В a + b
, b
преобразуется в unsigned int, (уступая UINT_MAX + 1 - 5
по правилу для unsigned to-подписанное преобразование).Результатом добавления 10 к этому значению является 5, по правилам арифметики без знака, а его тип - без знака int.В большинстве случаев тип выражения C не зависит от контекста, в котором оно появляется.(Обратите внимание, что все это не зависит от представления; преобразование и арифметика определяются исключительно в терминах числовых значений.)
Для второго вызова printf
результат прост: "%u"
ожидает аргументнапечатайте unsigned int
, и вы дали ему один.Он печатает "5\n"
.
Первый printf
немного сложнее."%d"
ожидает аргумент типа int
, но вы даете ему аргумент типа unsigned int
.В большинстве случаев несоответствие типов, подобное этому, приводит к неопределенному поведению, но есть специальное правило, согласно которому соответствующие подписанные и неподписанные типы взаимозаменяемы в качестве аргументов функции - до тех пор, пока значение представимо в обоих типах (как здесь),Таким образом, первый printf
также печатает "5\n"
.
Опять же, все это поведение определяется в терминах значений, а не представлений (за исключением требования, что данное значение имеет одинаковое представление в соответствующих знаковых и беззнаковыхтипов).Вы получите один и тот же результат в системе, где подписанные int и unsigned int имеют 37 бит, подписанный int имеет 7 битов заполнения, unsigned int имеет 11 битов заполнения, а подписанный int использует 1-е дополнение или знак-и-величинупредставление.(Насколько я знаю, в реальной жизни такой системы не существует.)