The following C/C++ code:
long long foo = -9223372036854775808LL; // -2^63
compiles (g++) with the warning
integer constant is so large that it is unsigned.
clang++ gives a similar warning.
Thanks to this bug report: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52661. I now understand why GCC gives this warning. Unfortunately, the response to the bug report didn't explain the reason for this behaviour very well.
Questions:
Unsigned integer constant is an integer constant which has the permissible range from 0 to 65536. Thus significance of declaring a constant as unsigned almost doubles the size of the largest possible value.
Unsigned constants are written with a terminal u or U , and the suffix ul or UL indicates unsigned long . Floating-point constants contain a decimal point ( 123.4 ) or an exponent ( 1e-2 ) or both; their type is double , unless suffixed. The suffixes f or F indicate a float constant; l or L indicate a long double .
This has to do with how the type of integer constants is defined.
First, as mentioned in the gcc bug report, -9223372036854775808LL
is actually two tokens: the unary -
operator and the integer constant 9223372036854775808LL
. So the warning applies only to the latter.
Section 6.4.4.1p5 of the C standard states:
The type of an integer constant is the first of the corresponding list in which its value can be represented.
Based on this, a decimal integer constant with no suffix will have type int
, long
, or long long
based on the value. These are all signed types. So anything value small enough to fit in an 8 bit or 16 bit type still has type int
, and a value too large for a 32 bit signed int will have type long
or long long
depending on the size of the type on that system. The same goes for a constant with the LL
suffix, but only the long long
type is tried.
The warning comes up because the value you're using doesn't fit in the above type list. Any lesser value will result in the value having a signed type meaning there's no conversion to unsigned.
As various more or less confused people in the bug report said, the integer constant 9223372036854775808LL
is too large to fit inside a long long
.
For decimal constants, the standard has a list in 6.4.4.1 (see the answer by @dbush) describing what types the compiler will try to give to an integer constant. In this case, the only valid option for type is (signed) long long
and it won't fit there. Then §6 under that table kicks in:
If an integer constant cannot be represented by any type in its list, it may have an extended integer type, if the extended integer type can represent its value. /--/
If the list contains both signed and unsigned types, the extended integer type may be signed or unsigned.
Extended integer type is a fuzzy but formal term in the standard. In this case the compiler apparenty tries to squeeze the constant into a unsigned long long
"extended integer type" where it fits. This isn't really guaranteed behavior but implementation-defined.
Then the unary -
operator is applied to the unsigned long long
which produces the warning.
This is the reason why library headers such as limits.h like to define LLONG_MIN
as
#define LLONG_MIN (-9223372036854775807LL - 1)
You could do something similar to avoid this warning. Or better yet, use LLONG_MIN
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With