Когда у вас есть бинарный оператор (один из +
-
*
/
%
<<
>>
&
|
^
==
!=
<
<=
>
>=
) между двумя целыми операндами разных типов, оба типа преобразуются в общий тип перед выполнением операции. Правила выбора типа преобразования (из раздела 6.3.1.8 стандарта C99):
Если оба операнда имеют одинаковый тип, дальнейшие преобразования не требуются.
В противном случае, если оба операнда имеют целочисленные типы со знаком или оба имеют беззнаковые
целочисленные типы, операнд с типом меньшего целого ранга преобразования
преобразован в тип операнда с большим рангом.
В противном случае, если операнд с целым типом без знака имеет ранг больше или
равен рангу типа другого операнда, то операнд с
целочисленный тип со знаком преобразуется в тип операнда с беззнаковым
целочисленный тип.
В противном случае, если тип операнда со знаком целого типа может представлять
все значения типа операнда с целым типом без знака, то
операнд с целым типом без знака преобразуется в тип
операнд со знаком целого типа.
В противном случае оба операнда преобразуются в целочисленный тип без знака
соответствует типу операнда со знаком целочисленного типа.
В этом случае char
может быть целым типом со знаком или без знака - его подпись определяется реализацией. К счастью, int
может представлять все возможные значения char
, независимо от того, подписан он или нет char
, при условии, что вы находитесь в системе, где char
s равны 8 битам, а int
s равны минимум 16 бит.
Если char
подписано, то применяется второй вышеприведенный абзац, поэтому оба операнда преобразуются в int
(тип с более высоким рангом; ранг определяется несколько сложным образом, но он по существу эквивалентен размеру бита типа). Поскольку 0x98, как знак char
, является отрицательным, он преобразуется в целое число -104, которое в этом случае меньше 7.
Если вместо char
не подписано, то вместо этого применяется четвертый абзац. Без знака char
будет преобразовано в 152 как int
, что больше 7.
Никогда не полагайтесь на то, что char
подписаны или не подписаны. Если вам нужны 8-разрядные целые числа определенной подписи, явно используйте signed char
или unsigned char
или используйте типы C99 int8_t
и uint8_t
, определенные int <stdint.h>
.
Очень легко быть укушенным незначительными ошибками, вызванными целочисленными правилами продвижения. Я настоятельно советую вам всегда компилировать с -Wall
с помощью gcc, который предупредит вас о сравнении целых чисел со знаком и без знака, которые часто являются причиной ошибок.