«Если рабочий хочет хорошо выполнять свою работу, он должен сначала заточить свои инструменты» — Конфуций, «Аналитики Конфуция. Лу Лингун»
титульная страница > программирование > Почему оператор сдвига вправо (`>>`) в C++ дает неожиданные результаты при сдвиге на 32 бита?

Почему оператор сдвига вправо (`>>`) в C++ дает неожиданные результаты при сдвиге на 32 бита?

Опубликовано 1 ноября 2024 г.
Просматривать:670

Why does the right shift operator (`>>`) в C дает неожиданные результаты при сдвиге на 32 бита?
>`) в C дает неожиданные результаты при сдвиге на 32 бита? " />

Неожиданное поведение оператора правого сдвига (1 >> 32)

В области программирования обычно используется оператор правого сдвига (>>) для выполнения побитовых операций, в частности для деления целого числа на степень двойки. Однако при сдвиге на большие значения может возникнуть странное поведение, как показано в следующем коде C:

int foo(int a, int b) {
   return a >> b;
}

int bar(uint64_t a, int b) {
   return a >> b;
}

int main() {
    std::cout > 32: " > 32) > (int)32: " > (int)32) 

Удивительно, но выходные данные этой программы показывают неожиданные результаты:

foo(1, 32): 1 // Should be 0
bar(1, 32): 0
1 >> 32: 0
(int)1 >> (int)32: 0

Обоснование этих результатов кроется во внутренней работе ЦП и компилятора.

Поведение функции foo()

В функции foo() операция сдвига выполняется без приведения, что заставляет процессор выполнять логический сдвиг вправо. Во многих архитектурах логический сдвиг вправо реализуется как >> (b % 32), фактически игнорируя старшие биты b. Следовательно, foo(1, 32) дает результат 1 >> (32 % 32), который оценивается как 1 >> 0, что дает 1.

Почему имеет значение приведение к 64-битному целому числу?

В функции bar() предоставляется 64-битное целое число без знака, гарантирующее, что результат гарантированно будет равен 0, поскольку b (32) меньше количества битов в операнде (64 ). Однако, когда b изменяется на 64, результат становится непредсказуемым и может по-прежнему давать 1.

Оптимизация компилятора

В случае 1 >> 32 и (int )1 >> (int)32, компилятор оптимизирует эти константные выражения во время компиляции. Стандарт определяет неопределенное поведение для сдвигов вправо, когда счетчик отрицательный или больше или равен длине операнда. Поскольку 32 превышает длину операнда, компилятор не может определить результат и выводит 0 как безопасный запасной вариант.

Поведение, специфичное для процессора

Реализация сдвига вправо операции могут различаться в зависимости от разных процессоров. В архитектурах x86/x86-64 логический сдвиг вправо фактически равен >> (b % 32 или 64), в зависимости от режима. Однако на процессорах ARM операция сдвига вправо гарантирует ноль для сдвигов, больших или равных 32.

Вывод

При работе с операторами сдвига вправо очень важно учитывать потенциальное неопределенное поведение, особенно когда количество сдвигов превышает длину операнда. Приведение к более широким целочисленным типам, таким как 64-битные целые числа, может обеспечить согласованные результаты на разных процессорах и компиляторах.

Последний учебник Более>

Изучайте китайский

Отказ от ответственности: Все предоставленные ресурсы частично взяты из Интернета. В случае нарушения ваших авторских прав или других прав и интересов, пожалуйста, объясните подробные причины и предоставьте доказательства авторских прав или прав и интересов, а затем отправьте их по электронной почте: [email protected]. Мы сделаем это за вас как можно скорее.

Copyright© 2022 湘ICP备2022001581号-3