attribuer une valeur à un long entier en utilisant gcc sur sparc solaris
Question
Je suis tombé sur quelque chose que je trouve plutôt étrange.Le programme des tests
int main(int argc, char* argv[])
{
cout<<"hello"<<endl;
long unsigned l = 0x12345678;
long long unsigned ll = 0x12345678;
cout<<sizeof(l)<<endl;
cout<<sizeof(ll)<<endl;
};
la sortie est :
hello
4
8
Aucune surprise là-bas.Le long int
a une taille de 4 octets et le long long
a une taille de 8 octets.Cependant, quand je le change pour que le long long soit attribué
long long unsigned ll = 0x123456789;
au moment de la compilation, j'obtiens
error: integer constant is too large for "long" type
Maintenant ce même test fait compiler si je force une build 64 bits en utilisant l'option -m64
.Est-ce que je fais quelque chose de mal ou est-ce un bug dans GCC ?
La solution
Changez cela en
long long unsigned ll = 0x123456789ULL; // notice the suffix
Sans le suffixe, le littéral est plus grand que le maximum unsigned long
valeur sur votre machine, et cela, selon C++03 (mais pas C++11, qui a long long
), est un comportement indéfini.Cela signifie que tout peut arriver, y compris une erreur de compilation.
Ça ne vaut rien aussi qu'il n'y ait pas long long
en C++03, son fonctionnement n'est donc pas garanti, vous comptez sur une extension.Vous feriez probablement mieux d’utiliser C++11 à la place.
Autres conseils
Le problème ici est que beaucoup de gens semblent regarder une ligne de code comme la vôtre :
unsigned long long ll = 0x123456789; /* ANTI-PATTERN! Don't do this! */
et raison "oh, le type est unsigned long long
, donc la valeur est unsigned long long
et il est attribué", mais ce n'est tout simplement pas ainsi que C fonctionne.Littéraux ont leur propre type, cela ne dépend pas du contexte dans lequel ils sont utilisés.Et le type de littéraux entiers est int
.
C’est la même erreur que lorsque les gens le font :
const double one_third = 1 / 3; /* ANTI-PATTERN! Don't do this! */
Penser "le type à gauche est double
, cela devrait donc attribuer 0,3333333...".Ce n’est (encore une fois !) pas ainsi que C fonctionne.Les types de littéraux divisés sont toujours int
, donc le côté droit est évalué exactement à 0, qui est ensuite converti en double
et stocké dans le one_third
variable.
Pour une raison quelconque, ce comportement est profondément peu intuitif pour de nombreuses personnes, c'est pourquoi il existe de nombreuses variantes de la même question.