Warning: this decimal constant is unsigned only in ISO C90

38,919

Solution 1

The rules for the types of decimal integer constants changed between the 1990 and 1999 editions of the ISO C standard.

In the 1990 version, an unsuffixed decimal integer constant's type is the first of int, long int, or unsigned long int in which its value can be represented. (C90 had no long long or unsigned long long type).

In the 1999 and 2011 versions, its type is one of int, long int, long long int; it's never of any unsigned type.

The type of a particular constant (such as 2147483648) will vary depending on the ranges of the integer types for the compiler you're using. If your compiler's long type happens to be 32 bits, then 2147483648 will be of type unsigned long if your compiler uses C90 rules, or of type long long if it uses C11 rules (long long is guaranteed to be at least 64 bits). The compiler is warning you about this.

You can add suffixes to specify the type of a constant -- but there's no suffix for plain signed int. You can add U for unsigned int, L for long, UL for unsigned long, and so forth.

It's important to keep in mind that -2147483648 is not an integer constant; rather 2147483648 by itself is an integer constant, and -2147483648 is an expression that applies a unary minus operator to that constant. Under C90 rules, if the constant is of type unsigned long, that's an unsigned unary minus, which under the rules of unsigned arithmetic yields the value 2147483648. Under C99 or C11 rules, 2147483648 is likely to be of type (signed) long long, and negating it yields -2147483648, also of type long long.

You'll sometimes see code that uses (-2147483647 - 1) to avoid this problem; given a 32-bit int, 2147483647 is of type int and the result of the expression yields the expected int value without overflow.

Of course if your compiler has different sizes for the integer types, this can become even more complicated.

UPDATE: When I wrote this, the default dialect for gcc was -std=gnu89. Since then, it's been changed to -std=gnu11 (or -std=gnu17 in unreleased versions). I'm not sure how that affects the warning.

Solution 2

Yes, that's one thing that isn't handled very well by the compiler. The problem is that during compilation, this is the number 2147483648 which is negated, and 2147483648 is out of range for an integer. Even if -2147483648 wouldn't be!

Anyway, to get rid of the warning, you can turn the constant into a 64 bit number by writing -2147483648LL.
That's overkill though, so the preferred way would be to use INT_MIN for the constant. But then you'll need to include <limits.h>.

Solution 3

Yes, 2147483648 is not a valid positive value because it is out of range for 2's complement on 32 bit machines, so they are just trying to warn you that on some compilers this may not give you the value you want if they don't handle the negation in a modern way.

I feel it's worth adding another answer to point out that if you look at most limits.h implementations, you'll see that they get around this using (-2147483647 - 1).

Share:
38,919

Related videos on Youtube

user1227514
Author by

user1227514

Updated on October 14, 2020

Comments

  • user1227514
    user1227514 over 3 years

    Piece of code :

    long rangeVar = 0;
    rangeVar = atol(p_value);
    
    if (rangeVar >= -2147483648 && rangeVar <= 2147483647)
    

    On compiling I get:

    warning: this decimal constant is unsigned only in ISO C90

    Thanks in Advance

    • Lindydancer
      Lindydancer about 12 years
      C90 does not have the long long type, which is the reason why it handles such numbers differently than C99.
    • TUNAPRO1234
      TUNAPRO1234 almost 11 years
      FYI: The correct answer is found here: stackoverflow.com/questions/2347936/…
  • Alexey Frunze
    Alexey Frunze about 12 years
    Not entirely correct/accurate. C89 says: The type of an integer constant is the first of the corresponding list in which its value can be represented. Unsuffixed decimal: int, long int, unsigned long int; unsuffixed octal or hexadecimal: .... So, for an old compiler or modern compiler working in some sort of compatibility mode 2147483648 will fail if it can't fit into unsigned long, not plain int. C99 extends that list with long long int and unsigned long long int and in C99 mode the suffix (U)LL is unnecessary. Of course, compiler bugs aren't unheard of either.
  • Mr Lister
    Mr Lister about 12 years
    How would you explain the warning then? I tested, and I got the same warning as the OP with gcc 4.3.2, and no warning when I used the LL suffix.
  • Alexey Frunze
    Alexey Frunze about 12 years
    It means gcc is not in C99 mode by default. If you add -std=c99, it will be and then produce a different warning: "comparison is always true due to limited range of data type". Surprise. I'm not really even sure what mode it's in by default and why.
  • Alexey Frunze
    Alexey Frunze about 12 years
    This says the default is gnu89, which is GNU dialect of ISO C90 (including some C99 features). This is the default for C code.
  • Mr Lister
    Mr Lister about 12 years
    @user1227514 Good, but have you read the comments as well? Did you also try if -std=c99 works (instead of changing the source)?
  • Grzegorz Szpetkowski
    Grzegorz Szpetkowski about 10 years
    Thank you for great and clear answer. For completeness it may be worth to add that 1999 edition on C standard mentioned about implementation-defined extended integer types. If none of types are sufficient, then constant can have such extended type as final one. For example in GCC (version 4.4.7) constant 9223372036854775808 (i.e. 2^63) is "promoted" to 16 bytes datatype __int128_t (despite the fact that it's not "true" EIT). Plese also note that these rules are slightly different for octal and hexadecimal representations, but I guess OP was only interested in decimal ones.
  • M.M
    M.M over 7 years
    The U suffix means unsigned but not necessarily unsigned int, e.g. if a decimal constant with just U is too large for unsigned int, it will have type unsigned long. Similarly, L will "upgrade" to long long if the value doesn't fit in a long.