a |= (1 << 31) results in unexepected value

105 views Asked by At

I made a reproducible code as below/

#include <stdio.h>

int main(void)
{
    long int a = 0x0;

    a |= (1 << 31);

    printf("a: 0x%lx\n", a);

}

I expect 'a' should be 0x0000000080000000.

but the value is given as

a: 0xffffffff80000000.

Why are upper 32 bits filled with 1 programmatically, and if I want to make 'a' as single one and all zero value, what can I do?

3

There are 3 answers

2
Sourav Ghosh On

Change

a |= (1 << 31);

to

a |= (1UL << 31);

1 is an int constant, which is signed int by deafult.

1
0___________ On

1 is a signed int. When you shift it 31 bits left you get a negative number of INT_MIN (assuming 32 bits integer and two's competent). Then when you assign it to the long int (assuming 64 bits) it is being signed extended to have the same negative value.

It is undefined behaviour by the C standard but most modern computers have arithmetic shift instructions and use two's complement coding.

You need to use an unsigned number instead:

int main(void)
{
    long int a = 0x0;

    a |= (1U << 31);

    printf("a: 0x%016lx\n", a);

}

https://godbolt.org/z/G95GYffPM

or you need to cast it to unsigned int before binary or.

int main(void)
{
    long int a = 0x0;

    a |= (unsigned int)(1 << 31);

    printf("a: 0x%016lx\n", a);

}

https://godbolt.org/z/bq3j4dWsc

0
Vlad from Moscow On

From the C Standard (6.5.7 Bitwise shift operators)

3 The integer promotions are performed on each of the operands. The type of the result is that of the promoted left operand.

So the type of the expression ( a << 31 ) used in this statement

a |= (1 << 31);

is the signed integer type int.

Further (the same C Standard section)

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. If E1 has a signed type and nonnegative value, and E1 × 2E2 is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined.

Provided that an object of the type int contains 32 bits and the most-significant bit is the sign bit then the value of the expression (1 << 31 ) is not representable in an object of the type int and hence the expression invokes undefined behavior.

You need to use at least unsigned integer type unsigned int as for example

a |= (1u << 31);

or unsigned long int

a |= (1lu << 31);

Pay attention to that the result depends on the size of the type long int. It can be equal either to 4 as the size of the type int or 8 as the type long long int.

Instead of writing manually 0x in the format string of the call of printf

printf("a: 0x%lx\n", a);

you could use flag # like

printf("a: %0#16lx\n", a);