web-dev-qa-db-fra.com

Attention: cette constante décimale n'est pas signée uniquement en ISO C90

Morceau de code:

long rangeVar = 0;
rangeVar = atol(p_value);

if (rangeVar >= -2147483648 && rangeVar <= 2147483647)

Lors de la compilation, j'obtiens:

avertissement: cette constante décimale n'est pas signée uniquement dans ISO C90

Merci d'avance

20
user1227514

Les règles pour les types de constantes entières décimales ont changé entre les éditions 1990 et 1999 de la norme ISO C.

Dans la version 1990, le type d'une constante entière décimale sans suffixe est le premier de int, long int Ou unsigned long int Dans lequel sa valeur peut être représentée. (C90 n'avait pas de type long long Ou unsigned long long).

Dans les versions 1999 et 2011, son type est l'un de int, long int, long long int; ce n'est jamais d'aucun type non signé.

Le type d'une constante particulière (comme 2147483648) Variera en fonction des plages des types entiers pour le compilateur que vous utilisez. Si le type long de votre compilateur est 32 bits, alors 2147483648 Sera de type unsigned long Si votre compilateur utilise les règles C90, ou de type long long Si il utilise les règles C11 (long long est garanti d'être au moins 64 bits). Le compilateur vous en avertit.

Vous pouvez ajouter des suffixes pour spécifier le type d'une constante - mais il n'y a pas de suffixe pour le signe simple int. Vous pouvez ajouter U pour unsigned int, L pour long, UL pour un long non signé, etc.

Il est important de garder à l'esprit que -2147483648 Est pas une constante entière; plutôt 2147483648 est en soi une constante entière, et -2147483648 est une expression qui applique un opérateur unaire moins à cette constante. Selon les règles C90, si la constante est de type unsigned long, C'est un non signé unaire moins, qui selon les règles de l'arithmétique non signée donne la valeur 2147483648. Selon les règles C99 ou C11, 2147483648 Est susceptible d'être de type (signé) long long, Et sa négation donne -2147483648, Également de type long long.

Vous verrez parfois du code qui utilise (-2147483647 - 1) Pour éviter ce problème; étant donné un int de 32 bits, 2147483647 est de type int et le résultat de l'expression donne la valeur attendue de int sans débordement.

Bien sûr, si votre compilateur a des tailles différentes pour les types entiers, cela peut devenir encore plus compliqué.

13
Keith Thompson

Oui, c'est une chose qui n'est pas très bien gérée par le compilateur. Le problème est que pendant la compilation, c'est le nombre 2147483648 qui est annulé, et 2147483648 est hors de portée pour un entier. Même si -2147483648 ne le serait pas!

Quoi qu'il en soit, pour vous débarrasser de l'avertissement, vous pouvez transformer la constante en un nombre 64 bits en écrivant -2147483648LL.
Mais c'est exagéré, donc la meilleure façon serait d'utiliser INT_MIN pour la constante. Mais vous devrez alors inclure <limits.h>.

10
Mr Lister

Oui, 2147483648 n'est pas une valeur positive valide car il est hors plage pour le complément à 2 sur les machines 32 bits, ils essaient juste de vous avertir que sur certains compilateurs, cela peut ne pas vous donner la valeur que vous souhaitez s'ils ne gèrent pas la négation d'une manière moderne.

Je pense qu'il vaut la peine d'ajouter une autre réponse pour souligner que si vous regardez la plupart des implémentations de limits.h, vous verrez qu'ils contournent cela en utilisant (-2147483647 - 1).

1
Peter M