Search code examples
cbitwise-andc17

Bitwise & over 32 bits


#include <stdio.h>
#include <limits.h>

int main()
{
    unsigned long long a = 9223372036854775808; // a = 2^63
    a = a & ~1;
    printf("%llu\n", a);
    printf("%d, %lld", INT_MAX, LLONG_MAX);
}

Output

9223372036854775808
2147483647, 9223372036854775807

This is the semantic of the ~ in C17(with my bold), 6.5.3.3.4.

The result of the ~ operator is the bitwise complement of its (promoted) operand (that is, each bit in the result is set if and only if the corresponding bit in the converted operand is not set). The integer promotions are performed on the operand, and the result has the promoted type. If the promoted type is an unsigned type, the expression ~E is equivalent to the maximum value representable in that type minus E.

This is the semantic of the unary & in C17, 6.5.10.3.

The usual arithmetic conversions are performed on the operands.

a is equal to 9223372036854775808 which is equal to 8000 0000 0000 0000(16).

An integer constant 1 without any suffix is the same as (int)1. Therefore ~1 == ~(int)1 == FFFF FFFE(16)(integer promotion doesn't happen by ~).

The type of FFFF FFFE(16) is converted to unsigned long long at
a = 8000 0000 0000 0000(16) & FFFF FFFE(16) by the usual arithmetic conversion. Therefore
a = 8000 0000 0000 0000(16) & FFFF FFFE(16) ==
a = 8000 0000 0000 0000(16) & 0000 0000 FFFF FFFE(16)

Finally,
a = a & ~1 ==
a = 8000 0000 0000 0000(16) & FFFF FFFE(16) ==
a = 8000 0000 0000 0000(16) & 0000 0000 FFFF FFFE(16) ==
a = 0000 0000 0000 0000(16)

But the output says as if
a = a & ~1 ==
a = 8000 0000 0000 0000(16) & FFFF FFFE(16) ==
a = 8000 0000 0000 0000(16) & FFFF FFFF FFFF FFFE(16) ==
a = 8000 0000 0000 0000(16)

My question is how the output is shown?


Solution

  • ~1 in the twos complement system (all modern system - including your PC use it) is -2.

    The binary representation of -2 in 4-byte long integer is 0xfffffffe.

    When you promote it to long long integer the value -2 is preserved but the binary representation changes: 0xffffffffffffffffe. This value is binary AND-ed with your variable a - so its value remains unchanged.

    if you want to prevent this behaviour you need to tell the compiler what size data you want to use:

        a = a & ~(unsigned)1;
    

    and it will behave as you expect

    https://godbolt.org/z/G6757W