Подтвердить что ты не робот

Операция сравнения для целых чисел без знака и знака

Смотрите этот фрагмент кода

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;
}   

Это дает результат: a МАЛАЯ: 1001

Я не понимаю, что здесь происходит. Как работает оператоp > здесь? Почему "a" меньше "b"? Если это действительно меньше, почему я получаю положительное число (1001) как разницу?

4b9b3361

Ответ 1

Двоичные операции между различными интегральными типами выполняются в "общем" типе, определяемом так называемыми обычными арифметическими преобразованиями (см. спецификацию языка, 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 приводит к поведению undefined, поэтому значение, которое вы видите напечатанным (даже если оно имеет логическое детерминированное объяснение на практике), совершенно не имеет смысла с точки зрения языка C.

Изменить: Собственно, я мог ошибаться в части поведения undefined. Согласно спецификации языка C, общая часть диапазона соответствующего типа с подписью и без знака должна иметь идентичное представление (подразумевая, согласно сноске 31, "взаимозаменяемость в качестве аргументов для функций" ). Таким образом, результат выражения a - b не указан 1001, как описано выше, и, если я что-то не упускаю, законно печатать это значение без знака с помощью спецификатора %d, поскольку оно попадает в положительный диапазон int. Печать (unsigned) INT_MAX + 1 с помощью %d будет undefined, но 1001u в порядке.

Ответ 2

В типичной реализации, где 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.)

Ответ 3

Вы выполняете сравнение без знака, то есть сравниваете 1000 до 2 ^ 32 - 1.

Выход подписан из-за% d в printf.

N.B. иногда поведение, когда вы смешиваете подписанные и неподписанные операнды, зависит от компилятора. Я думаю, что лучше избегать их и делать броски, когда сомневаешься.

Ответ 4

Найдите простой способ сравнения, возможно, полезный, когда вы не можете избавиться от объявления без знака (например, [NSArray count]), просто принудительно введите "unsigned int" в "int".

Пожалуйста, поправьте меня, если я ошибаюсь.

if (((int)a)>b) {
    ....
}

Ответ 5

Аппаратное обеспечение предназначено для сравнения подписанных и подписанных без знака.

Если вы хотите получить арифметический результат, сначала преобразуйте значение unsigned в более крупный подписанный тип. В противном случае компилятор предположим, что сравнение действительно между неподписанными значениями.

И -1 представлен как 1111..1111, поэтому это очень большое количество... Самое большое... Когда интерпретируется как unsigned.