@Mercury13
Программист на «си с крестами» и не только

Почему сдвиг знаковый?

//----------------------------------------------------------------------------//
/// Clipping unsigned minus
///
template <class T>
T cu_minus(T a, T b)
{
    T r = a - b;
    if (r>a) return 0;
    return r;
}

    uint32_t lowerBits(unsigned n)
    {
        unsigned shift = cu_minus(32u, n);
        uint32_t r = uint32_t(0xFFFFFFFFu) >> shift;
        return r;
    }

Почему lowerBits(0) равен 4294967295?
Функцию «clipping unsigned minus» привёл только для полноты, в ней ошибки нет (максимум поведение, определяемое реализацией, и меня это устраивает). Что необычного в сдвигах?

А с этой версией, надеюсь, всё в порядке?
uint32_t lowerBits(unsigned n)
    {
        if (n >= 32)
            return 0xFFFFFFFFu;
        return uint32_t(0x7FFFFFFF) >> (31u - n);
    }
  • Вопрос задан
  • 209 просмотров
Решения вопроса 1
@MiiNiPaa
Раздел [expr.shift] в стандарте С++ говорит, что результат сдвига не определён, если правый операнд отрицателен или больше или равен ширине левого операнда в битах.

Большинство компиляторов не пытаются определить возможное неопределённое поведение и как-то его поправить, и просто генерируют наиболее прямой код, наплевав на возможность UB.

На x86 при попытке сдвинуть 32битное число, процессор берёт значение сдвига по модулю 32 (обнуляет все биты регистра кроме 5 младших). Соответственно 32 превращается в 0.
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы