long long в C / C ++


84

Я випробовую цей код на компіляторі C ++ GNU і не можу зрозуміти його поведінку:

#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.

Чому?


8
Зараз може бути запізно, але для майбутніх читачів я пропоную вам скористатися <stdint.h>і використовувати uint64_t. Щоб відобразити 64-бітове значення,printf( "%" PRIu64 "\n", val);
энтузиазмгик

@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 );
Пастух

Відповіді:


147

Букви 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

8
Причиною цього раніше була проблема не в тому, що C ++ не був достатньо `` розумним '', щоб визначити тип літералу за типом змінної, якій призначається, це було б просто тому, що розширення компілятора не реалізувало розширене ціле число типу, який би добре працював зі стандартною мовою. Тепер у C ++ є такі правила, що будь-які розширені цілочисельні типи будуть краще інтегруватися зі стандартом: open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1988.pdf
bames53

4
@unwind Я думаю, що відповідь слід редагувати відповідно до цих пропозицій.
Антоніо


4

Це залежить від того, в якому режимі ви компілюєте. long long не є частиною стандарту C ++, а лише (зазвичай) підтримується як розширення. Це впливає на тип літералів. Десяткові цілочисельні літерали без будь-якого суфікса завжди мають тип int, якщо int є достатньо великим, щоб представляти число, інакше довше. Якщо число навіть занадто велике на довгий час, результат визначається реалізацією (ймовірно, це лише число типу long int, яке було усічено для зворотної сумісності). У цьому випадку вам потрібно явно використовувати суфікс LL, щоб увімкнути довге довге розширення (на більшості компіляторів).

Наступна версія C ++ буде офіційно підтримувати long long таким чином, що вам не знадобиться жоден суфікс, якщо ви явно не хочете, щоб сила типу літералу була принаймні long long. Якщо число неможливо представити довго, компілятор автоматично спробує використовувати long long навіть без суфіксу LL. Я вважаю, що це також поведінка C99.


1

ваш код тут чудово компілюється (навіть якщо цей рядок не прокоментований. довелося змінити його на

num3 = 100000000000000000000;

щоб почати отримувати попередження.


Який компілятор? У C ++ цілочисельний літерал є меншим від int або long, ніж він вміщується. У C99 це найменший з int, long, long long. Отже, коли довго прикручується до C ++ як нестандартного розширення, можливо, ваш компілятор також прийняв правила C99 для літералів.
Steve Jessop

gcc версії 4.3.2 (Debian 4.3.2-1.1) на 64-бітній системі Linux.
Омрі Ядан

@SteveJessop, можливо, трохи пізно: але довгий - НЕ обов'язково 64 біти. Здебільшого це так, але у вас немає гарантій, що воно буде скрізь. Єдиною гарантією, яку ви маєте, є те, що вона є принаймні настільки ж велика, як int, а це, у свою чергу, принаймні настільки ж велика, як коротка int, яка, у свою чергу, є принаймні такою ж, як char. Нарешті, символ визначається як досить великий , щоб представляти кожен символ в реалізація мови основним кодуванням (зазвичай 8-біт).
pauluss86

@ pauluss86: Я не говорив про гарантії. Омрі сказав, що він використовував gcc 4.3.2 на 64-бітовій системі Debian. Я зауважив, що це пояснює те, що він бачив, оскільки (я випадково знав, що загальновідомо) gcc налаштовано за замовчуванням у таких системах для використання 64 біт longвідповідно до LP64 ABI цієї ОС.
Steve Jessop

@SteveJessop Я не припускаю, що ваш коментар помилковий! Тільки вказуючи на те, що припущення про те, що довгий - це завжди скрізь 64 біти, на жаль, на думку багатьох людей, є небезпечним.
pauluss86
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.