После прочтения этого вопроса о сравнениях со знаком / без знака (они появляются каждые пару дней, я бы сказал):
Я удивлялся, почему у нас нет должных подписанных беззнаковых сравнений, а вместо этого этот ужасный беспорядок?Возьмите вывод из этой маленькой программы:
#include <stdio.h>
#define C(T1,T2)\
{signed T1 a=-1;\
unsigned T2 b=1;\
printf("(signed %5s)%d < (unsigned %5s)%d = %d\n",#T1,(int)a,#T2,(int)b,(a<b));}\
#define C1(T) printf("%s:%d\n",#T,(int)sizeof(T)); C(T,char);C(T,short);C(T,int);C(T,long);
int main()
{
C1(char); C1(short); C1(int); C1(long);
}
Скомпилированный с моим стандартным компилятором (gcc, 64bit), я получу это:
char:1
(signed char)-1 < (unsigned char)1 = 1
(signed char)-1 < (unsigned short)1 = 1
(signed char)-1 < (unsigned int)1 = 0
(signed char)-1 < (unsigned long)1 = 0
short:2
(signed short)-1 < (unsigned char)1 = 1
(signed short)-1 < (unsigned short)1 = 1
(signed short)-1 < (unsigned int)1 = 0
(signed short)-1 < (unsigned long)1 = 0
int:4
(signed int)-1 < (unsigned char)1 = 1
(signed int)-1 < (unsigned short)1 = 1
(signed int)-1 < (unsigned int)1 = 0
(signed int)-1 < (unsigned long)1 = 0
long:8
(signed long)-1 < (unsigned char)1 = 1
(signed long)-1 < (unsigned short)1 = 1
(signed long)-1 < (unsigned int)1 = 1
(signed long)-1 < (unsigned long)1 = 0
Если я скомпилирую для 32-битного, результатто же самое, за исключением того, что:
long:4
(signed long)-1 < (unsigned int)1 = 0
«Как?»все это легко найти: просто перейдите к разделу 6.3 стандарта C99 или главе 4 C ++ и найдите пункты, описывающие, как операнды преобразуются в общий тип, и это может сломаться, если общий тип интерпретирует отрицательные значения.
А как же "Почему?"Как мы видим, символ «<» дает сбой в 50% случаев, также он зависит от конкретных размеров типов, поэтому он зависит от платформы.Вот несколько моментов, которые следует учитывать: </p>
Процесс преобразования и сравнения на самом деле не является ярким примером для Правила наименьшего сюрприза
НадеюсьНе верьте, что существует код, основанный на предположении, что (short)-1 > (unsigned)1
и не написано террористами.
Это все ужасно, когда выВы находитесь в C ++ с шаблоном кода, потому что вам нужно волшебство черты типа, чтобы связать правильный "<". </p>
В конце концов, сравнивая подписанные и беззнаковые значения разных типов is легко реализовать:
signed X < unsigned Y -> (a<(X)0) || ((Z)a<(Z)b) where Z=X|Y
Предварительная проверка обходится дешево и также может быть оптимизирована компилятором, если a> = 0 может быть статически доказано.
Итак, вот мой вопрос:
Не нарушит ли язык или существующий код, если мы добавим безопасные сравнения со знаком / без знака в C / C ++?
(«Будет ли это нарушать язык» означает, что нам нужно было бы внести значительные изменения в различные части языка, чтобы учесть это изменение)
ОБНОВЛЕНИЕ: Я выполнилэто на моем старом добром Turbo-C ++ 3.0 и получил такой вывод:
char:1
(signed char)-1 < (unsigned char)1 = 0
Почему (signed char)-1 < (unsigned char) == 0
здесь?