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

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

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) как различие?

40
задан R Sahu 3 December 2016 в 07:16
поделиться

3 ответа

У вас довольно мощные возможности композиции с Option:

def getURL : Option[URL]
def getDefaultURL : Option[URL]


val (host,port) = (getURL orElse getDefaultURL).map( url => (url.getHost,url.getPort) ).getOrElse( throw new IllegalStateException("No URL defined") )
-121--809616-

Q1: Она работает отсюда, и, вероятно, из многих других мест. Однако обратите внимание, что геолокация с IP-адресов не очень надежная наука. Вы получите местоположение вашего интернет-провайдера, которое может быть довольно далеко, и, кроме того, базы данных IP-местоположения не всегда соответствуют последним изменениям, поэтому у вас может не быть данных для конкретного IP-адреса, что, вероятно, происходит в вашем случае.

MaxMind, который предлагает популярную базу данных IP-адрес, опубликованную статистику по своей базе данных:

Q2: Единственный способ получить геолокацию с IP-адреса через API-интерфейс Google Maps v3 - это использовать тот же метод, что и в примере, который вы предоставили . Однако если вы обнаружите, что любая другая база данных геолокации, например MaxMind GeoLite City , является более точной для вашей страны, вы можете сделать геолокацию с IP-адресов самостоятельно, а не делегировать ее в Google Maps.

-121--4950790-

Двоичные операции между различными интегральными типами выполняются в пределах «общего» типа, определяемого так называемыми обычными арифметическими преобразованиями (см. языковую спецификацию, 6.3.1.8). В данном случае тип «common» - без знака int . Это означает, что int операнд (ваш b ) будет преобразован в неподписанный int перед сравнением, а также с целью вычитания.

При преобразовании -1 в неподписанную int получается максимально возможное значение неподписанной int (такое же, как UINT _ MAX ). Нет необходимости говорить, что оно будет больше, чем ваше неподписанное значение 1000 , что означает, что a > b действительно неверно и a действительно мало по сравнению с (неподписанный) b . Ветвь if в коде должна быть преобразована в ветвь else , что и было замечено в эксперименте.

К вычитанию применяются те же правила преобразования. Ваш a-b действительно интерпретируется как a - (неподписанный) b , и результат имеет тип неподписанный int . Такое значение не может быть напечатано со спецификатором формата % d , так как % d работает только со значениями со знаком . Ваша попытка напечатать его с помощью % d приводит к неопределенному поведению, поэтому значение, которое вы видите напечатанным (даже если оно имеет логическое детерминированное объяснение на практике), совершенно бессмысленно с точки зрения языка Си.

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

48
ответ дан 27 November 2019 в 01:45
поделиться

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

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

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

0
ответ дан 27 November 2019 в 01:45
поделиться

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

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

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

.
14
ответ дан 27 November 2019 в 01:45
поделиться
Другие вопросы по тегам:

Похожие вопросы: