web-dev-qa-db-fra.com

Comment distinguer automatiquement le court du long au moment de la compilation?

Je suis ravi d'utiliser les variables auto dans mes programmes C++. Je sais que les variables déclarées avec auto utilisent des règles de modèle pour déduire les types de variables, mais je ne sais pas comment cela fonctionne pour les types numériques. Supposons que j'ai:

auto foo = 12;

Le type de foo pourrait raisonnablement être int ou même unsigned char. Mais supposons que plus tard dans mon programme, je fasse quelques calculs et attribue à foo une valeur de 4 milliards. À ce stade, je voudrais que foo devienne de type unsigned int ou peut-être long.

Comment les compilateurs peuvent-ils anticiper les valeurs qui seront attribuées plus tard dans le programme?

22
David Lobron

Le compilateur fonctionne avec les informations présentes qui, dans votre cas, sont le littéral entier 12. Il en déduit donc que le foo est de type int. Il n'anticipe rien. Vous pouvez utiliser le suffixe littéral entier approprié:

auto foo = 12ul;

pour forcer le foo à être déduit comme unsigned long. Vous ne pouvez pas définir la variable comme étant de type int, puis en bas de la ligne, attendez-vous à ce que le compilateur la transforme en un autre type simplement parce que vous avez attribué une valeur différente qui ne rentrera pas dans le type précédemment utilisé. Si vous le faisiez, cela entraînerait simplement un débordement d'entier qui est un comportement indéfini.

Pour plus d'informations sur le sujet, consultez la référence spécificateur automatique et déduction de type automatique .

50
Ron

"Le type de foo pourrait raisonnablement être int ou même un caractère non signé"

Non ça ne peut pas. Chaque expression en C++ a un type, qui est clairement défini dans le langage. Dans votre cas, l'expression est un littéral entier, donc le type correspond au littéral. De quel type il s'agit spécifiquement, est défini par les règles :

Le type du littéral

Le type du littéral entier est le premier type dans lequel la valeur peut tenir, à partir de la liste des types qui dépend de la base numérique et du suffixe entier utilisé.

pas de suffixe - int, long int, long long int (depuis C++ 11)

"Comment les compilateurs peuvent-ils anticiper les valeurs qui seront attribuées plus tard dans le programme?"

Ça ne peut pas. Le type est déterminé lorsque vous déclarez la variable et ne peut pas être modifié ultérieurement.

23
Slava

Le type de foo pourrait raisonnablement être un caractère int ou même non signé

Il pourrait être beaucoup de choses, mais en fait est une seule chose.

Le littéral entier 12 a le type int.

Période.

Mais supposons plus tard dans mon programme, je fais quelques calculs et attribue à foo une valeur de 4 milliards. À ce stade, je voudrais que foo ait un type non signé int ou peut-être long. Comment les compilateurs peuvent-ils anticiper les valeurs qui seront attribuées plus tard dans le programme?

Ils ne le peuvent pas, et ils ne le font pas. Le type de foo ne changera pas. foo n'a pas de type auto (ça n'existe pas); il a le type int. Votre programme sera désormais comme si vous aviez écrit int foo = 12;. La déduction/automatisation s'arrête là.

10

À ce stade, je voudrais que foo ait le type unsigned int ou peut-être long.

Ce n'est pas ainsi que la langue fonctionne. Une variable ne peut pas avoir son type modifié lors de l'exécution. Si vous définissez et initialisez une variable comme auto foo = 12;, cela signifie exactement la même chose que int foo = 12;, indépendamment de toute affectation future, car le type de 12 est int.

Comment les compilateurs peuvent-ils anticiper les valeurs qui seront attribuées plus tard dans le programme?

Ils n'ont pas à le faire. Les valeurs attribuées ultérieurement seront converties en type de variable. Si la valeur est hors plage pour ce type, les règles exactes dépendent des types avec lesquels vous traitez.

5
user743382

Mon conseil est que ce n'est pas un bon endroit pour utiliser auto. Vous savez quels facteurs déterminent le type dont vous avez besoin et ils ne peuvent pas être déduits du contexte immédiat. (Cependant, si vous pouvez écrire vos variables sous la forme d'affectations statiques uniques, cela ne se produira jamais.)

Si vous savez que la variable doit pouvoir contenir une valeur d'au moins 4 milliards, déclarez-la comme unsigned long ou long long int. Ou, si vous voulez vraiment coder de manière défensive contre les choix malheureux pour la largeur de ces types (tels que les plates-formes où long est de 32 bits de large pour prendre en charge le code hérité, mais la taille du mot natif est de 64 bits), déclarez-le comme uint_fast32_t ou int_fast64_t. Ou si vous voulez le plus petit, pas le plus rapide, uint_least32_t. (Parfois, le code le plus rapide est celui qui conserve le plus de valeurs dans le cache!)

Si ce que vous voulez vraiment est le type signé ou non signé le plus rapide pouvant contenir une valeur de 4 milliards, dites ce que vous voulez dire!

4
Davislor

Personnellement, je n'utiliserais pas auto pour ces constantes immédiates, mais où la valeur provient d'un autre appel de méthode, ou affectée d'une autre variable.

Si vous voulez un moyen de définir une variable pour qu'elle corresponde au type d'une autre variable, vous pouvez donc interagir avec elle, mais vous voulez attribuer une valeur constante, puis utilisez decltype pour vous assurer que sa taille est compatible:

decltype(otherVar) myVar = 1234;
myVar += otherVar;  // will work just as well as otherVar += myVar

Dans tous les cas, le type est spécifié par la constante littérale, et un 12 non décoré définira un int.

Cependant, vous pouvez décorer votre constante avec U, pour la rendre non signée, ou L pour la rendre longue, ou même LL pour la rendre super longue. Il n'y a pas d'équivalent pour le forcer court ou char, malheureusement!

1
Gem Taylor