long long en C / C ++

84

J'essaye ce code sur le compilateur C ++ de GNU et je suis incapable de comprendre son comportement:

#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;
}

Lorsque je décommente la ligne commentée, le code ne se compile pas et donne une erreur:

erreur: la constante entière est trop grande pour le type long

Mais, si le code est compilé tel quel et exécuté, il produit des valeurs bien supérieures à 10000000000.

Pourquoi?

sud03r
la source
8
Il est peut-être trop tard maintenant, mais pour les futurs lecteurs, je vous suggère de l'utiliser <stdint.h>et de l'utiliser uint64_t. Pour afficher une valeur 64 bits,printf( "%" PRIu64 "\n", val);
enthousiastegeek
@enthusiasticgeek <stdint.h>inclus,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 );
Gardien

Réponses:

147

Les lettres 100000000000 constituent une constante entière littérale, mais la valeur est trop grande pour le type int. Vous devez utiliser un suffixe pour changer le type du littéral, c'est-à-dire

long long num3 = 100000000000LL;

Le suffixe LLtransforme le littéral en type long long. C n'est pas assez "intelligent" pour conclure cela à partir du type de gauche, le type est une propriété du littéral lui-même, pas le contexte dans lequel il est utilisé.

se détendre
la source
47
Retour quand cette réponse a été écrit , il était probablement correct, mais maintenant la norme C ++ indique que le type d'un littéral entier sans suffixe est le premier int, long intet long long intdont la valeur peut être représentée. [C ++ §2.14.2 / 2] Par conséquent, maintenant il n'est pas nécessaire d'ajouter le suffixe 'LL' sur un littéral entier qui est trop grand pour les autres types.
bames53
8
La raison pour laquelle c'était un problème auparavant n'était pas parce que C ++ n'était pas assez `` intelligent '' pour déterminer le type littéral à partir du type de la variable assignée, cela aurait simplement été parce que l'extension du compilateur n'a pas implémenté l'entier étendu tapez de telle sorte que cela fonctionne bien avec la langue standard. C ++ a maintenant des règles telles que tous les types entiers étendus s'intégreront mieux avec la norme: open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1988.pdf
bames53
4
@unwind Je pense que la réponse devrait être modifiée en fonction de ces suggestions.
Antonio
26

Essayer:

num3 = 100000000000LL;

Et BTW, en C ++, il s'agit d'une extension de compilateur, le standard ne définit pas long long, c'est une partie de C99.

Arkaitz Jimenez
la source
11
Eh bien, C ++ 11 définit maintenant long long
Mohamed El-Nakib
4

Cela dépend dans quel mode vous compilez. long long ne fait pas partie du standard C ++ mais seulement (généralement) pris en charge comme extension. Cela affecte le type de littéraux. Les littéraux entiers décimaux sans suffixe sont toujours de type int si int est suffisamment grand pour représenter le nombre, long sinon. Si le nombre est encore trop grand pendant longtemps, le résultat est défini par l'implémentation (probablement juste un nombre de type long int qui a été tronqué pour la compatibilité descendante). Dans ce cas, vous devez explicitement utiliser le suffixe LL pour activer l'extension longue longue (sur la plupart des compilateurs).

La prochaine version de C ++ prendra officiellement en charge long long de sorte que vous n'aurez pas besoin de suffixe à moins que vous ne vouliez explicitement que la force du type du littéral soit au moins longue. Si le nombre ne peut pas être représenté en long, le compilateur essaiera automatiquement d'utiliser long long même sans suffixe LL. Je pense que c'est aussi le comportement du C99.

sellibitze
la source
1

votre code compile ici très bien (même avec cette ligne non commentée. a dû le changer en

num3 = 100000000000000000000;

pour commencer à recevoir l'avertissement.

Omry Yadan
la source
Quel compilateur? En C ++, un littéral entier est le plus petit de int ou long dans lequel il tient. En C99, c'est le plus petit des int, long, long long. Ainsi, lorsque vous vous associez longtemps à C ++ en tant qu'extension non standard, votre compilateur a peut-être également adopté les règles C99 pour les littéraux.
Steve Jessop
gcc version 4.3.2 (Debian 4.3.2-1.1) sur un système Linux 64 bits.
Omry Yadan le
@SteveJessop Un peu en retard peut-être: mais long n'est PAS forcément 64 bits. La plupart du temps, c'est le cas, mais vous n'avez aucune garantie que ce sera partout. La seule garantie que vous avez est qu'il est au moins aussi gros qu'un int, qui à son tour est au moins aussi gros qu'un int court, qui à son tour est au moins aussi gros qu'un caractère. Enfin, char est défini comme suffisamment grand pour représenter chaque caractère du jeu de caractères de base de l' implémentation (généralement 8 bits).
pauluss86
@ pauluss86: Je ne parlais pas de garanties. Omry a dit qu'il utilisait gcc 4.3.2 sur un système Debian 64 bits. J'ai observé que cela expliquait ce qu'il voyait depuis (je le savais comme une question de connaissances générales) gcc est configuré par défaut sur de tels systèmes pour utiliser un 64 bits longen ligne avec l'ABI LP64 de cet OS.
Steve Jessop
@SteveJessop Je ne dis pas que votre commentaire est faux! Soulignant seulement que l'hypothèse selon laquelle un long fait toujours 64 bits partout, ce que pensent malheureusement beaucoup de gens, est dangereuse.
pauluss86