long long в C / C ++

84

Я пробую этот код на компиляторе GNU C ++ и не могу понять его поведение:

#include <stdio.h>;

int main()
{
    int  num1 = 1000000000;
    long num2 = 1000000000;
    long long num3;
    //num3 = 100000000000;
    long long num4 = ~0;

    printf("%u %u %u", sizeof(num1), sizeof(num2), sizeof(num3));
    printf("%d %ld %lld %llu", num1, num2, num3, num4);
    return 0;
}

Когда я раскомментирую прокомментированную строку, код не компилируется и выдает ошибку:

ошибка: целочисленная константа слишком велика для длинного типа

Но если код компилируется как есть и выполняется, он дает значения, намного превышающие 10000000000.

Почему?

Sud03r
источник
8
Возможно, сейчас уже слишком поздно, но для будущих читателей я предлагаю вам использовать <stdint.h>и использовать uint64_t. Чтобы отобразить 64 битное значение,printf( "%" PRIu64 "\n", val);
enthusiasticgeek
@enthusiasticgeek <stdint.h>включен,uint64_t a = 0xffffffffffffff; printf( "%" PRIu64 "\n",a ); : error: expected ‘)’ before ‘PRIu64’ printf( "%" PRIu64 "\n",a ); :: warning: spurious trailing ‘%’ in format [-Wformat=] printf( "%" PRIu64 "\n",a );
пастух
#define __STDC_FORMAT_MACROS 1См stackoverflow.com/questions/14535556/...
enthusiasticgeek

Ответы:

148

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

long long num3 = 100000000000LL;

Суффикс LLпревращает литерал в тип long long. C недостаточно "умен", чтобы сделать вывод из типа слева, тип - это свойство самого литерала, а не контекст, в котором он используется.

размотать
источник
47
Назад , когда этот ответ был написан он был , наверное , правильно, но теперь стандарт C ++ говорит о том , что тип целочисленного литерала, без суффикса является первым из int, long intи long long intв котором его значение может быть представлено. [C ++ §2.14.2 / 2] Поэтому теперь нет необходимости добавлять суффикс 'LL' к целочисленному литералу, который слишком велик для других типов.
bames53 04
8
Причина, по которой это было проблемой раньше, заключалась не в том, что C ++ не был достаточно `` умным '', чтобы определить литеральный тип по типу присвоенной переменной, это было просто потому, что расширение компилятора не реализовало расширенное целое типа так, чтобы он хорошо работал со стандартным языком. В C ++ теперь есть правила, согласно которым любые расширенные целочисленные типы будут лучше интегрироваться со стандартом: open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1988.pdf
bames53 04
4
@unwind Я думаю, что ответ следует отредактировать в соответствии с этими предложениями.
Антонио
26

Пытаться:

num3 = 100000000000LL;

И, кстати, в C ++ это расширение компилятора, стандарт не определяет long long, это часть C99.

Аркаитц Хименес
источник
11
Что ж, C ++ 11 теперь определяет long long
Мохамед Эль-Накиб
4

Это зависит от того, в каком режиме вы компилируете. long long не является частью стандарта C ++, а поддерживается (обычно) только как расширение. Это влияет на тип литералов. Десятичные целочисленные литералы без суффикса всегда относятся к типу int, если int достаточно велик для представления числа, в противном случае - long. Если число даже слишком велико в течение длительного времени, результат определяется реализацией (вероятно, это просто число типа long int, которое было усечено для обратной совместимости). В этом случае вы должны явно использовать суффикс LL, чтобы включить long long расширение (в большинстве компиляторов).

Следующая версия C ++ будет официально поддерживать long long, так что вам не понадобится суффикс, если только вы явно не хотите, чтобы тип литерала был как минимум long long. Если число не может быть представлено длинным, компилятор автоматически попытается использовать long long даже без суффикса LL. Я считаю, что это тоже поведение C99.

Sellibitze
источник
1

ваш код компилируется здесь нормально (даже с этой строкой без комментариев. пришлось изменить ее на

num3 = 100000000000000000000;

чтобы начать получать предупреждение.

Омри Ядан
источник
Какой компилятор? В C ++ целочисленный литерал - это наименьшее из int или long, в которое он помещается. В C99 это наименьшее из int, long, long long. Поэтому, когда вы используете C ++ как нестандартное расширение, возможно, ваш компилятор также принял правила C99 для литералов.
Стив Джессоп,
gcc версии 4.3.2 (Debian 4.3.2-1.1) в 64-битной системе Linux.
Омри Ядан,
@SteveJessop Возможно, немного поздно: но long НЕ обязательно 64 бита. В большинстве случаев это так, но у вас нет гарантий, что это будет везде. Единственная гарантия, что у вас есть, это то, что он по крайней мере такой же большой, как int, который, в свою очередь, по крайней мере, такой же большой, как короткий int, который, в свою очередь, по крайней мере, такой же большой, как char. Наконец, символ определяется как достаточно большой , чтобы представлять каждый символ в реализация языка основной кодировкой (обычно 8-бит).
pauluss86 08
@ pauluss86: Я не говорил о гарантиях. Омри сказал, что он использовал gcc 4.3.2 в 64-битной системе Debian. Я заметил, что это объясняет то, что он видел, поскольку (я знал, что в общих чертах) gcc настроен по умолчанию в таких системах на использование 64-битной версии longв соответствии с LP64 ABI этой ОС.
Стив Джессоп
@SteveJessop Я не считаю, что ваш комментарий неправильный! Только указание на то, что предположение о том, что long всегда везде 64 бита, что, к сожалению, многие думают, опасно.
pauluss86 09