Неожиданный вывод при побитовой операции правого сдвига


int main()
{

    int x = 0xff0000ff;
    int N_BITS = sizeof (int) * 8;  /* 32 */
    int l = 0x0;

    printf ("Right shift expected result: %xn", 0x80000000 >> (31));

    l = (x & (0x00000001 << (N_BITS - 1)));
    printf ("l = %xn", l);

    /* Right Shift l by 31 bits */
    l = l >> 31;
    printf ("l after right shift by 31 bits: %xn", l);
}
~              

Вывод:

Right shift expected result: 1
l = 80000000
l after right shift by 31 bits: ffffffff

~
Сдвиг вправо 0x80000000 на 31 бит должен привести к 0x00000001, как показано в самом первом выводе. Почему выходные данные отличаются здесь, когда переменная l смещена на 31 бит вправо?

1 2

1 ответ:

Предполагая результат

l = (x & (0x00000001 << (N_BITS - 1)));

Является 0x80000000 (см. ниже это не гарантируется, так как выражение вызывает неопределенное поведение).

В системе дополнения двойки, 0x80000000 является отрицательным значением (INT_MIN).

l = l >> 31;

C говорит, что эта операция >> определена реализацией. В вашей системе он выполняет расширение знака: знаковый бит распространяется.

(C11, 6.5. 7p4) " если E1 имеет знаковый тип и отрицательное значение, то результирующее значение равно реализация-определена."

Наконец, почему:

0x000001 << (N_BITS - 1)

Вызывает неопределенное поведение.

Из уст лошади (Курсив мой):

(C11, 6.5. 7p4) " результатом E1 Если E1 имеет знак тип и неотрицательное значение, а также E1 × 2^^E2 представимо в типе результата, то есть результирующее значение; в противном случае поведение не определено. "