Тип целочисленных литералов не int по умолчанию? - PullRequest
32 голосов
/ 13 ноября 2011

Я только что ответил на этот вопрос , который спросил, почему повторение до 10 миллиардов в цикле for занимает намного больше времени (OP фактически прервал его через 10 минут), чем повторение до 1 миллиарда:

for (i = 0; i < 10000000000; i++)

Теперь мой и многие другие очевидный ответ состояли в том, что это произошло из-за того, что переменная итерации была 32-разрядной (которая никогда не достигает 10 миллиардов), а цикл получил бесконечный цикл.

Но хотя я понял эту проблему, мне все еще интересно, что на самом деле происходит внутри компилятора?

Поскольку литерал не был добавлен с L, он должен ИМХО также иметь тип int и, следовательно, 32-битный. Таким образом, из-за переполнения должен быть нормальный int в пределах диапазона, чтобы быть достижимым. Чтобы на самом деле признать, что он не может быть достигнут из int, компилятору нужно знать, что он равен 10 миллиардам, и, следовательно, рассматривать его как константу более 32 бит.

Получается ли такой литерал в подходящем (или, по крайней мере, определяемом реализацией) диапазоне (по крайней мере, 64-битном, в данном случае) автоматически, даже если не добавлен L, и это стандартное поведение? Или что-то другое происходит за кулисами, например, UB из-за переполнения (действительно ли целочисленное переполнение действительно UB)? Некоторые цитаты из Стандарта могут быть хорошими, если таковые имеются.

Хотя первоначальный вопрос был C, я также ценю ответы C ++, если таковые имеются.

Ответы [ 3 ]

34 голосов
/ 13 ноября 2011

Что касается C ++:

C ++ 11, [lex.icon] ¶2

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

И таблица 6 для литералов без суффиксов и десятичных констант дает:

int
long int
long long int

(что интересно, для шестнадцатеричных или восьмеричных констант также допускаются unsigned типы - но каждый из них идет после соответствующего подписанного в списке)

Итак, ясно, что в этом случае константа была интерпретирована как long int (или long long int, если long int было слишком 32-битным).

Обратите внимание, что "слишком большие литералы" должны приводить к ошибке компиляции:

Программа плохо сформирована, если одна из ее единиц перевода содержит целочисленный литерал, который не может быть представлен ни одним из разрешенных типов.

(там же, №3)

, что быстро видно в этом примере , что напоминает нам, что ideone.com использует 32-битные компиляторы.

<ч />

Теперь я увидел, что вопрос был о C ... ну, это более или менее то же самое:

C99, §6.4.4.1

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

список такой же, как в стандарте C ++.

<ч />

Добавление: и C99, и C ++ 11 допускают также, чтобы литералы имели «расширенные целочисленные типы» (то есть другие целочисленные типы, зависящие от реализации), если все остальное не удается. (C ++ 11, [lex.icon] ¶3; C99, §6.4.4.1 after5 после таблицы)

11 голосов
/ 13 ноября 2011

Из моего проекта стандарта C, помеченного ISO / IEC 9899: проект комитета TC2 - 6 мая 2005 г. , правила очень похожи на правила C ++, найденные Маттео:

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

Suffix      Decimal Constant          Octal or Hexadecimal Constant
-------------------------------------------------------------------
none        int                       int
            long int                  unsigned int
            long long int             long int
                                      unsigned long int
                                      long long int
                                      unsigned long long int

u or U      unsigned int              unsigned int
            unsigned long int         unsigned long int
            unsigned long long int    unsigned long long int

l or L      long int                  long int
            long long int             unsigned long int
                                      long long int
                                      unsigned long long int
Both u or U unsigned long int         unsigned long int
and l or L  unsigned long long int    unsigned long long int

ll or LL    long long int             long long int
                                      unsigned long long int

Both u or U unsigned long long int    unsigned long long int
and ll or LL 
1 голос
/ 13 ноября 2011

Мне все еще интересно, что на самом деле происходит внутри компилятора

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

10000000000

400054f:
mov    -0x4(%rbp),%eax
mov    %eax,-0x8(%rbp)
addl   $0x1,-0x4(%rbp)
jmp    40054f <main+0xb>

так что он просто скомпилировал его в бесконечный цикл, если заменить 10000000000 на 10000:

....
test   %al,%al
jne    400551
...