The C standard states that a long int
is at least 4 bytes - on my system it is 8 bytes.
This means I can store values up to 2^ 63 -1 in a long
and 2 64 -1 in an unsigned long
.
However, when the following code is compiled with the -Wall
flag it gives the warning [Wimplicitly-unsigned-literal]
:
int main (int argc, char ** argv) {
unsigned long a;
a = 18446744073709551615; // 2^64-1
}
If I use 2 63 -1 (9223372036854775807) instead, it compiles with no warnings (as expected - 2 63 -1 will fit in a signed long int
).
For a project I needed to have the maximum value in an unsigned long
, and I discovered that (9223372036854775807 << 1) + 1
will not raise this warning. My teacher then suggested that I could use the ULONG_MAX
defined in limits.h
and this gave no warnings.
Why can't I do this without a warning saying it was converted implicitly - when I declared it explicitly?
Per the C standard, the type of a decimal constant without a suffix is int
, long int
, or long long int
, specifically the first of those that is sufficient to represent the value. In your C implementation, none of those can represent 18446744073709551615, because it is too large.
In order to accommodate you, the compiler is making its type unsigned long
. Technically, this does not conform to the C standard, so the compiler is warning you.
In this case, no harm is caused, because you are assigning the value to an unsigned long
. But there are situations in which using the wrong type can cause problems, so generally you should append a suffix to such constants to ensure they match how they are intended to be used. In this case, a u
is sufficient; as with unsuffixed types, the compiler will decide whether to use unsigned int
, unsigned long int
, or unsigned long long int
depending on the magnitude of the number and the capabilities of the types.
You declared it explicitly, but without an U, which would make it unsigned. As there is no signed integer constant with this value, it implicitly makes it unsigned, providing you with the information that you'd better make it explicit.
Do so with a = 18446744073709551615U;
.
Check out this fancy table from the standard (6.4.4.1p5) :
which explains how integer literals are fitted into integer types.
Basically, because your literal is decimal and doesn't have a suffix, it tries to fit into the following types:
int
long int
long long int
Since it won't fit into long long int
, you're getting the warning you're getting.
If you add a U
( u
) suffix (or UL
or UL
or the lowercase variants):
unsigned long a = 18446744073709551615U;
you won't have that problem, because you'll move to the promotion sequence:
unsigned int
unsigned long int
unsigned long long int
(or the appropriate subsets for UL
and UL
) and the literal will fit at unsigned long int
(if that's indeed the first unsigned type with no less than 64 usable bits, as it usually is).
Alternatively, you can turn the warning off by switching to an octal or hexadecimal literal:
unsigned long a = 0xFFFFFFFFFFFFFFFF;
unsigned long octal_a = 01777777777777777777777;
as for these the promotion sequence is:
int
unsigned int
long int
unsigned long int
long long int
unsigned long long int
as per the linked table, which again, allows them to fit into the first 64-bit large unsigned type (usually unsigned long int
).
What you should absolutely not do is:
(9223372036854775807 << 1) + 1 //don't do this!
as this invokes undefined behavior by breaking 6.5.7p4 regardless of whether a warning is generated or not.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.