Язык C выполняет «Обычные арифметические преобразования» для многих операторов - преобразования описаны в 6.3.1.8 стандарта C99. Для целочисленных операндов выполняются первые рекламные акции, и это является причиной вашей проблемы. Акции описаны в 6.3.1.1 (Арифметические операнды / булевы, символы и целые числа), в которых, среди прочего, сказано:
Если int может представлять все значения исходного типа, значение преобразуется в int; в противном случае он конвертируется в беззнаковое целое. Они называются целочисленными акциями. Все остальные типы не изменяются целочисленными акциями.
Повышение применяется только к объектам или выражениям с целочисленным типом с рангом меньше int
и unsigned int
(или битовых полей).
Итак, в вашем выражении:
t1 < t2-1
даже если переменные unsigned short
, они повышаются до int, поскольку на вашей платформе int
может представлять все значения unsigned short
. Таким образом, выражение оценивается с использованием int
типов, и не происходит никакого переполнения - часть выражения t2-1
заканчивается как отрицательная 1.
В выражении:
s1 < s2-1
типы unsigned long
не повышаются, поскольку они имеют более высокий «ранг», чем int
/ unsigned int
, поэтому выражение оценивается с использованием арифметики без знака (с вычитанием из вычитания) и с помощью s2-1
подвыражение дает очень большое число, а не отрицательное 1.
Как указано в комментарии в виде символа lb, если в платформе int
реализован как 16-битный тип (что разрешено - например, в MS-DOS), повышение unsigned short
будет равно unsigned int
вместо int
, поскольку int
не сможет представлять все значения unsigned short
(unsigned short
должно быть не менее 16 бит). В этом случае оба оператора if
будут иметь значение true.