Операция сравнения на не подписываемых и подписанных целых числах
Вопрос
Смотрите этот фрагмент кода
int main()
{
unsigned int a = 1000;
int b = -1;
if (a>b) printf("A is BIG! %d\n", a-b);
else printf("a is SMALL! %d\n", a-b);
return 0;
}
Это дает выход: а маленький: 1001
Я не понимаю, что здесь происходит. Как> оператор здесь работает? Почему «меньше, чем" b "? Если это действительно меньше, почему я получаю положительное число (1001) в качестве разницы?
Решение
Бинарные операции между различными интегральными типами выполняются в рамках «общего» типа, определяемого так называемым Обычные арифметические преобразования (См. Спецификацию языка, 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
Это хорошо.
Другие советы
На типичной реализации, где int
32 -битный, -1 при преобразовании в unsigned int
составляет 4 294 967 295, что действительно ≥ 1000.
Даже если вы относитесь к вычитанию в unsigned
Мир, 1000 - (4,294,967,295) = -4,294,966,295 = 1,001
Что вы получаете.
Вот почему gcc
выплюнет предупреждение, когда вы сравниваете unsigned
с signed
. Анкет (Если вы не видите предупреждения, передайте -Wsign-compare
флаг.)
Вы делаете без подписного сравнения, то есть сравнивая от 1000 до 2^32 - 1.
Вывод подписан из -за %d в printf.
NB Иногда поведение, когда вы смешиваете подписанные и неподписанные операнды, является специфичным для компилятора. Я думаю, что лучше избегать их и делать броски, когда сомневаемся.
Найдите простой способ сравнения, может быть, полезно, когда вы не можете избавиться от беспигнированного объявления (например, [nsarray count]), просто вынуждают «без знака» к «int».
Пожалуйста, поправьте меня, если я ошибаюсь.
if (((int)a)>b) {
....
}
Аппаратное обеспечение предназначено для сравнения подписанного с подписанным и неподписанным с Unsigned.
Если вам нужен арифметический результат, сначала преобразуйте значение без знака в более крупный подписанный тип. В противном случае компилятор будет предполагать, что сравнение действительно находится между беззнатными значениями.
И -1 представлен как 1111..1111, так что это очень большое количество ... самое большое ... когда интерпретируется как без подписи.
#include<stdio.h>
int main()
{
int a = 1000;
signed int b = -1, c = -2;
printf("%d",(unsigned int)b);
printf("%d\n",(unsigned int)c);
printf("%d\n",(unsigned int)a);
if(1000>-1){
printf("\ntrue");
}
else
printf("\nfalse");
return 0;
}
Для этого вам нужно понять приоритет операторов
Реляционные операторы работают слева направо ... так что когда это придет
if (1000> -1)
Тогда, прежде всего, он изменится -1 на беспигнированное целое число, потому что int по умолчанию рассматривается как без знака, и он варьируется больше, чем подписанное число
-1 превратится в беззначительный номер, он превратится в очень большое число
При сравнении a> b, где a in unsigned int type, а B - тип int, b тип, отлитый до беспигного int Таким образом, подписанное значение int -1 преобразуется в максимальное значение без знака ** (диапазон: от 0 до (2^32) -1) ** Таким образом, A> B IE, (1000> 4294967296) становится ложным. Следовательно, еще петля printf ("a маленький! %d n", ab); выполнен.