2012-03-30 1 views
15

morceau de code:Attention: cette constante décimale est seulement non signé dans la norme ISO C90

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

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

sur la compilation I get:

avertissement: cette constante décimale est non signée que dans ISO C90

Merci à l'avance

+1

C90 n'a pas le type 'long long', ce qui explique pourquoi il traite ces nombres différemment de C99. – Lindydancer

+2

FYI: La bonne réponse est trouvée ici: http://stackoverflow.com/questions/2347936/cant-get-rid-of-this-decimal-constant--unsigned-only-in-iso-c90- avertissement – natersoz

Répondre

9

Oui, c'est une chose qui n'est pas très bien traité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 nombre entier. Même si -2147483648 ne serait pas! Quoi qu'il en soit, pour vous débarrasser de l'avertissement, vous pouvez transformer la constante en un nombre de 64 bits en écrivant .
C'est exagéré cependant, donc le moyen préféré serait d'utiliser INT_MIN pour la constante. Mais alors vous devrez inclure <limits.h>.

+2

Pas tout à fait correct/précis. C89 dit: 'Le type d'une constante entière est le premier de la liste correspondante dans laquelle sa valeur peut être représentée. Décimal non suffixé: int, long int, unsigned long int; octal ou hexadécimal non suffixé: ... '. Donc, pour un vieux compilateur ou un compilateur moderne fonctionnant dans une sorte de mode de compatibilité, 2147483648 va échouer s'il ne peut pas rentrer dans 'unsigned long', pas dans' 'unf'. C99 étend cette liste avec 'long long int' et' unsigned long long int' et en mode C99 le suffixe (U) LL est inutile. Bien sûr, les bogues du compilateur ne sont pas inconnus non plus. –

+0

Comment expliqueriez-vous l'avertissement alors? J'ai testé, et j'ai eu le même avertissement que l'OP avec gcc 4.3.2, et aucun avertissement quand j'ai utilisé le suffixe LL. –

+0

Cela signifie que gcc n'est pas en mode C99 par défaut. Si vous ajoutez '-std = c99', cela produira un avertissement différent:" la comparaison est toujours vraie en raison d'une plage limitée de type de données ". Surprise. Je ne suis même pas vraiment sûr du mode par défaut et pourquoi. –

1

Oui, 2147483648 n'est pas une valeur positive valide car il est hors de portée pour le complément 2 sur les machines 32 bits, donc ils essaient juste de vous avertir que sur certains compilateurs cela peut ne pas vous donner la valeur que vous voulez ne pas gérer 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 le contourneront en utilisant (-2147483647 - 1).

+0

astuce awsome !! – malat

12

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

Dans la version 1990, un type de constante de nombre entier décimal unsuffixed est le premier de int, long int ou unsigned long int dans laquelle 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 des suivants: int, long int, long long int; ce n'est jamais de type non signé.

Le type d'une constante particulière (telle que 2147483648) varie en fonction des plages de types entiers du compilateur que vous utilisez. Si le type long du compilateur se trouve être 32 bits, 2147483648 sera de type unsigned long si votre compilateur utilise les règles C90, ou de type long long s'il utilise les règles C11 (long long est garanti à au moins 64 bits). Le compilateur vous avertit à ce sujet.

Vous pouvez ajouter des suffixes pour spécifier le type d'une constante - mais il n'y a pas de suffixe pour la signature standard int. Vous pouvez ajouter U pour unsigned int, L pour long, UL pour unsigned long, et ainsi de suite.

Il est important de garder à l'esprit que -2147483648 est et non une constante entière; plutôt 2147483648 par lui-même est une constante entière et -2147483648 est une expression qui applique un opérateur moins unaire à cette constante.En vertu des règles C90, si la constante est de type unsigned long, il s'agit d'un nombre unaire non signé non signé, qui, selon les règles de l'arithmétique non signée, donne la valeur 2147483648. Sous les règles C99 ou C11, 2147483648 est susceptible d'être de type (signé) long long, et de le renoncer il 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 32 bits, 2147483647 est de type int et le résultat de l'expression donne la valeur attendue 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é.

+0

Merci pour votre réponse. Par souci de complétude, il peut être utile d'ajouter cette édition de 1999 sur la norme C mentionnée à propos des types entiers étendus définis par l'implémentation. Si aucun des types n'est suffisant, alors la constante peut avoir un type étendu tel que le type final. Par exemple, dans GCC (version 4.4.7), la constante '9223372036854775808' (c'est-à-dire 2^63) est" promue "à 16 octets type de données' __int128_t' (malgré le fait que ce n'est pas "vrai" EIT). Veuillez également noter que ces règles sont légèrement différentes pour les représentations octales et hexadécimales, mais je suppose que OP ne s'intéressait qu'aux variables décimales. –

+1

Le suffixe «U» signifie non signé mais pas nécessairement «non signé int», par ex. Si une constante décimale avec simplement 'U' est trop grande pour' unsigned int', elle aura le type 'unsigned long'. De même, 'L' va" mettre à jour "à' long long' si la valeur ne tient pas dans un 'long'. –

Questions connexes