Подтвердить что ты не робот

Тип целочисленных литералов не int по умолчанию?

Я просто ответил на этот вопрос, в котором спрашивали, почему итерация до 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, я также ценю ответы на С++, если они существуют.

4b9b3361

Ответ 1

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

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

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

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

int
long int
long long int

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

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

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

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

(ibidem, ¶3)

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


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

C99, §6.4.4.1

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

который аналогичен стандарту С++.


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

Ответ 2

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

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 

Ответ 3

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

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

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