Ответ 1
Двоичные операции между различными интегральными типами выполняются в "общем" типе, определяемом так называемыми обычными арифметическими преобразованиями (см. спецификацию языка, 6.3.1.8). В вашем случае "общий" тип unsigned int
. Это означает, что операнд int
(ваш b
) преобразуется в unsigned int
перед сравнением, а также для выполнения вычитания.
Когда -1
преобразуется в unsigned int
, результат представляет собой максимально возможное значение unsigned int
(такое же, как UINT_MAX
). Излишне говорить, что он будет больше, чем значение без знака 1000
, что означает, что a > b
действительно ложно, а a
действительно мало по сравнению с (unsigned) b
. if
в вашем коде должен разрешаться в ветки else
, что и было в вашем эксперименте.
Те же правила преобразования применяются к вычитанию. Ваш a-b
действительно интерпретируется как a - (unsigned) b
, а результат имеет тип unsigned int
. Такое значение не может быть напечатано с помощью спецификатора формата %d
, так как %d
работает только с подписанными значениями. Ваша попытка распечатать его с помощью %d
приводит к поведению undefined, поэтому значение, которое вы видите напечатанным (даже если оно имеет логическое детерминированное объяснение на практике), совершенно не имеет смысла с точки зрения языка C.
Изменить: Собственно, я мог ошибаться в части поведения undefined. Согласно спецификации языка C, общая часть диапазона соответствующего типа с подписью и без знака должна иметь идентичное представление (подразумевая, согласно сноске 31, "взаимозаменяемость в качестве аргументов для функций" ). Таким образом, результат выражения a - b
не указан 1001
, как описано выше, и, если я что-то не упускаю, законно печатать это значение без знака с помощью спецификатора %d
, поскольку оно попадает в положительный диапазон int
. Печать (unsigned) INT_MAX + 1
с помощью %d
будет undefined, но 1001u
в порядке.