The Standard specifies that hexadecimal constants like 0x8000 (larger than fits in a signed integer) are unsigned (just like octal constants), whereas decimal constants like 32768 are signed long. (The exact types assume a 16-bit integer and a 32-bit long.) However, in regular C environments both will have the same representation, in binary 1000 0000 0000 0000
.
Is a situation possible where this difference really produces a different outcome? In other words, is a situation possible where this difference matters at all?
Yes, it can matter. If your processor has a 16-bit int
and a 32-bit long
type, 32768 has the type long
(since 32767 is the largest positive value fitting in a signed 16-bit int
), whereas 0x8000 (since it is also considered for unsigned int
) still fits in a 16-bit unsigned int
.
Now consider the following program:
int main(int argc, char *argv[])
{
volatile long long_dec = ((long)~32768);
volatile long long_hex = ((long)~0x8000);
return 0;
}
When 32768 is considered long
, the negation will invert 32 bits,
resulting in a representation 0xFFFF7FFF with type long
; the cast is
superfluous.
When 0x8000 is considered unsigned int
, the negation will invert
16 bits, resulting in a representation 0x7FFF with type unsigned int
;
the cast will then zero-extend to a long
value of 0x00007FFF.
Look at H&S5, section 2.7.1 page 24ff.
It is best to augment the constants with U
, UL
or L
as appropriate.
On a 32 bit platform with 64 bit long
, a
and b
in the following code will have different values:
int x = 2;
long a = x * 0x80000000; /* multiplication done in unsigned -> 0 */
long b = x * 2147483648; /* multiplication done in long -> 0x100000000 */
Another examine not yet given: compare (with greater-than or less-than operators) -1 to both 32768 and to 0x8000. Or, for that matter, try comparing each of them for equality with an 'int' variable equal to -32768.
Assuming int
is 16 bits and long
is 32 bits (which is actually fairly unusual these days; int
is more commonly 32 bits):
printf("%ld\n", 32768); // prints "32768"
printf("%ld\n", 0x8000); // has undefined behavior
In most contexts, a numeric expression will be implicitly converted to an appropriate type determined by the context. (That's not always the type you want, though.) This doesn't apply to non-fixed arguments to variadic functions, such as any argument to one of the *printf()
functions following the format string.
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