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