If my understanding of the left shift operator and little endianness is correct, then the value of x
in the following should be 0
on little endian machines.
uint64_t x = ((uint64_t)1<<63);
(uint64_t)1
in memory will look like 0x0100000000000000
and left shifting by 63 will change that to 0x0000000000000000
which is 0
. So x
should be 0
.
But when I run the following on my x86-64 machine
int main()
{
uint64_t x = ((uint64_t)1)<<63;
printf("%lu\n", x);
}
The output I get is 9223372036854775808
.
What am I getting wrong here?
CodePudding user response:
(uint64_t)1
has the value 0x0000000000000001
. How this value is represented on the memory shoudln't affect the calculation.
Shifting this value to left by 63 yields 0x8000000000000000
, which is 9223372036854775808
in decimal.
What you did wrong is the format specifier. You should use PRIu64
(defined in inttypes.h
) to print uint64_t
. %lu
is for unsigned long
and passing data having wrong type invokes undefined behavior.
#include <stdio.h>
#include <inttypes.h>
int main(void)
{
uint64_t x = ((uint64_t)1)<<63;
printf("%" PRIu64 "\n", x);
}
CodePudding user response:
The shift operator does not depend on little or big endianness. For unsigned integers it evaluates like (The C Standard, 6.5.7 Bitwise shift operators)
4 The result of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are filled with zeros. If E1 has an unsigned type, the value of the result is E1 × 2E2, reduced modulo one more than the maximum value representable in the result type
That is as the arithmetic operation E1 × 2^E2.
So for example the expression
1u << 1
is equivalent to 1u * 2
(1u * 2 ^ 1
).