Операция сравнения на не подписываемых и подписанных целых числах

StackOverflow https://stackoverflow.com/questions/2084949

  •  21-09-2019
  •  | 
  •  

Вопрос

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

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

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

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

    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); выполнен.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top