Операция сравнения для целых чисел без знака и со знаком - PullRequest
36 голосов
/ 18 января 2010

Посмотреть этот фрагмент кода

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

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

Ответы [ 7 ]

46 голосов
/ 18 января 2010

Бинарные операции между различными целочисленными типами выполняются в рамках «общего» типа, определяемого так называемыми обычными арифметическими преобразованиями (см. Спецификацию языка, 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 общая часть диапазона соответствующего целочисленного типа со знаком и без знака должна иметь идентичное представление (что подразумевает, согласно сноске 31, «взаимозаменяемость в качестве аргументов функций»). Таким образом, результатом выражения a - b является беззнаковое 1001, как описано выше, и, если я что-то упустил, допустимо напечатать это конкретное беззнаковое значение со спецификатором %d, поскольку оно попадает в положительный диапазон int. Печать (unsigned) INT_MAX + 1 с %d будет неопределенной, но 1001u - это нормально.

14 голосов
/ 18 января 2010

В типичной реализации, где int является 32-разрядным, -1 при преобразовании в unsigned int составляет 4 294 967 295, что действительно ≥ 1000.

Даже если вы обрабатываете вычитание в unsignedworld, 1000 - (4,294,967,295) = -4,294,966,295 = 1,001 что вы и получаете.

Вот почему gcc выдаст предупреждение при сравнении unsigned с signed.(Если вы не видите предупреждение, пройдите флаг -Wsign-compare.)

0 голосов
/ 12 сентября 2018
 #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;
 }

Для этого нужно понять приоритет операторов

  1. Реляционные операторы работают слева направо ... так что когда дело доходит

    если (1000> -1)

тогда сначала он изменит -1 на целое число без знака, потому что int по умолчанию рассматривается как число без знака и его диапазон больше номера со знаком

-1 изменится на число без знака, оно превратится в очень большое число

0 голосов
/ 10 июля 2018

при сравнении a> b, где a - тип unsigned int, а b - тип int, b - тип, приведенный к unsigned int , поэтому значение -1 со знаком int преобразуется в значение MAX без знака ** ( диапазон: от 0 до (2 ^ 32) -1) ** Таким образом, a> b, то есть (1000> 4294967296) становится ложным. Следовательно, иначе цикл printf ("a МАЛЕНЬКИЙ!% D \ n", a-b); выполнен.

0 голосов
/ 20 апреля 2012

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

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

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

0 голосов
/ 02 апреля 2012

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

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

if (((int)a)>b) {
    ....
}
0 голосов
/ 18 января 2010

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

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

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

...