2013-06-25 3 views
34
#include <stdio.h> 
main() 
{ 
    if (sizeof(int) > -1) 
     printf("True"); 
    else 
     printf("False"); 
} 

Он печатает False. Почему sizeof() не возвращает значение в if?Оператор sizeof() в операторе if-statement

+20

Включите предупреждения компилятора. – Kos

+26

'(sizeof (int)> -1)' = '(4u> -1)' = '(4u> -1u)' = '(4u> -1u)' или '(4u> 4294967295uu)' потому что '- 1u == 4294967295u' = 'False' =' 0' –

ответ

51
  1. sizeof не является функцией, это оператор. Скобки не являются частью имени оператора.
  2. Это не так, потому что генерируемое значение имеет неподписанный тип size_t, что приводит к «обычным арифметическим преобразованиям», в которых -1 преобразуется в unsigned, и в этом случае это очень большое число.

В основном вы сравниваете 4 > 0xffffffffu, или что-то близкое к этому как минимум. See this question для деталей.

+4

Строго говоря, здесь нет целочисленного продвижения, а скорее _balancing_ (формально называемого «обычные арифметические преобразования»). – Lundin

+10

преобразование '-1' в целое число без знака всегда дает максимальное значение, даже если представление не является дополнением двух. – Christoph

+0

Благодаря @Lundin и Christoph, отредактирован. – unwind

22

Неподписанное и подписанное целочисленное продвижение (точнее, «обычные арифметические преобразования», если быть более точным). sizeof дает значение типа size_t, и по сравнению с неподписанным значением (которое size_t есть), -1 продвигается к этому типу и переполняется и становится огромным.

Целое число без знака переполнения имеет вполне определенное поведение и должно быть принято, как по модулю, где 2^widthwidth является число битов в конкретном типе целого числа без знака. Таким образом, если у вас есть 32-битная size_t и int, например, ваше сравнение будет эквивалентно

if (4 > 4294967295u) 

, который, очевидно, неверно.

+0

Отличный ответ, но не будет ли он переполнен, а не переполнен? – C0deH4cker

+1

@ C0deH4cker Ну, все зависит от того, как вы его интерпретируете :) Я предпочитаю использовать «underflow» для чисел с плавающей запятой, когда число «x

+0

А вот этот ответ (http://programmers.stackexchange.com/questions/32893/is-int-min-1-an-underflow-or-overflow) объясняет это, а также почему я был в замешательстве. – C0deH4cker

12
  • Операнды оператора> в заявлении, если есть sizeof(int) и -1.
  • sizeof(int) имеет тип size_t, который гарантированно является целым числом без знака. На практике, size_t, скорее всего, будет, по крайней мере, размером с unsigned int в любой системе.
  • -1 имеет тип int, что эквивалентно signed int.
  • Не существует целочисленных рекламных акций, так как оба операнда имеют достаточно большие целые типы.
  • Затем два операнда сбалансированный в соответствии с правилом C формально называемым обычными арифметическими преобразованиями.

Это состояние (C11 6.3.1.8):

...

В противном случае, если тип операнда с подписью целочисленного типа может представлять все значения типа операнда с непознанным целым типом , то операнд с целым целым числом без знака преобразуется в тип операнда со знаком целочисленного типа.

В противном случае оба операнда преобразуются в целочисленный тип без знака, соответствующий тип операнда со знаком целочисленного типа.

  • Последнее вышеперечисленное будет, так как (подпись) int не может приспосабливать все значения в size_t.
  • Таким образом, -1 преобразуется в целое число без знака. На практике, size_t, скорее всего, эквивалентен либо unsigned int, либо unsigned long. Что бы ни случилось, когда вы сохраняете -1 в такой переменной, это поведение, определяемое реализацией.
  • На компьютере с дополнительным компьютером (99,9% всех компьютеров в мире) -1 будет интерпретироваться как 0xFFFFFFFF (количество FF зависит от размера int в данной системе).
  • 4 > 0xFFFFFFFF оценивает значение false.
+8

«Что бы ни случилось, когда вы сохраняете -1 в такой переменной, это поведение, определяемое реализацией». Umm, единственная зависящая от реализации вещь - ширина 'size_t'. преобразование '-1' в неподписанный тип обязано приводить к максимальному значению этого типа по стандарту. –

+0

@ DanielFischer Что я имел в виду, так это то, что способ распознавания целочисленного поведения является impl.defined. C позволяет дополнять друг друга, дополнять и т. Д. – Lundin

+0

Где «и так далее» расширяется до «подписанного магната» или «знака и величины», в зависимости от того, какое имя вы предпочитаете. Таким образом, независимо от того, является ли преобразование просто усечением/переинтерпретацией/расширением знака или изменением битового шаблона по-другому, определяется реализацией, да. Но это не имеет значения, не так ли? Важным является результат. –

1

Просто проверить это и увидеть для себя

#include <stdio.h> 
main() { 
    unsigned int a=4; 
    int b = -1; 
    //this is what you're doing 
    printf("%u vs %u\n", a, (unsigned int)b); 
    //this is what you want to do instead 
    printf("%d vs %d\n", (int)a, b); 
} 
2

Sizeof является оператором, который приводит к беззнаковому долгому междунару. Следовательно, при сравнении unsigned long int с -1, который сохраняется как 0xffffffff (размер int равен 4 байтам).

-1 по умолчанию обозначено целое число. Но, в сравнении между подписанным int и unsigned int, компилятор идет с неявным typecasting подписанного int в unsigned int. Это приводит к тому, что знак без знака -1 будет приблизительно равен значению 4.6giga.

Следовательно, выход false.