Бинарные операции между различными интегральными типами выполняются в рамках «общего» типа, определенного с помощью так называемых обычных арифметических преобразований (см спецификации языка, 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
приводит к неопределенному поведению, поэтому значение, которое вы видите напечатанным (даже если оно имеет логическое детерминированное объяснение на практике), совершенно не имеет смысла с точки зрения языка C.
Редактировать: На самом деле, я могу ошибаться в неопределенной части поведения. Согласно спецификации языка C, общая часть диапазона соответствующего типа с подписью и без знака должна иметь идентичное представление (подразумевая, согласно сноске 31, «взаимозаменяемость в качестве аргументов для функций»).Таким образом, результат выражения a - b
является неподписанным 1001
, как описано выше, и если я что-то не упускаю, законно печатать это значение без знака с помощью спецификатора %d
, так как оно попадает в положительный диапазон от int
. Печать (unsigned) INT_MAX + 1
с %d
будет не определена, но 1001u
в порядке.
Если вы используете флаг компилятора -Wsign-compare, вы получите предупреждение для сравнения. Вы всегда должны использовать -Wall (который включает -Wsign-compare). См. [Здесь] (http://www.a-coding.com/2010/12/beware-usigned-integers.html) для других способов избежать этой проблемы. – Aleph7
Смотрите это сообщение для получения дополнительной информации: http://stackoverflow.com/q/10474769/844882 –
@ Aleph7 - технически это не совсем правильно, -Wsign-compare - это только inc. с -Wall * if * вы компилируете C++. Он не включен для C (см. Здесь https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html). Я протестировал его и могу подтвердить, что код выше не дает предупреждения в -Wall, но делает с -Wsign-compare (я использую gcc (Ubuntu 5.2.1-22ubuntu2) 5.2.1 20151010) – bph