Правый сдвиг и целое число со знаком
В моем компиляторе следующий псевдо-код (значения заменены двоичным):
sint32 word = (10000000 00000000 00000000 00000000);
word >>= 16;
создает a word
с битовым полем, который выглядит так:
(11111111 11111111 10000000 00000000)
Мой вопрос в том, могу ли я полагаться на это поведение для всех платформ и компиляторов С++?
Ответы
Ответ 1
Из следующей ссылки:
INT34-C. Не переносите выражение на отрицательное число бит или больше или равно количеству битов, которые существуют в операнде
Несоответствующий пример кода (правый сдвиг)
Результатом E1 >> E2
является E1
смещение по правому краю E2
. Если E1
имеет неподписанный тип, или если E1
имеет подписанный тип и неотрицательное значение, значение результата является неотъемлемой частью частного E1/2 E2. Если E1
имеет подписанный тип и отрицательное значение, результирующее значение определяется реализацией и может быть либо арифметическим (подписанным) сдвигом:
![Arithmetic (signed) shift]()
или логический (беззнаковый) сдвиг:
![Logical (unsigned) shift]()
Этот несовместимый пример кода не может проверить, является ли правый операнд больше или равен ширине продвинутого левого операнда, позволяя поведение undefined.
unsigned int ui1;
unsigned int ui2;
unsigned int uresult;
/* Initialize ui1 and ui2 */
uresult = ui1 >> ui2;
Предположение о том, реализуется ли сдвиг вправо как арифметический (подписанный) сдвиг или логический (беззнаковый) сдвиг, также может привести к уязвимостям. См. Рекомендацию INT13-C. Используйте побитовые операторы только для неподписанных операндов.
Ответ 2
Нет, вы не можете полагаться на это поведение. Правильное смещение отрицательных величин (которое я предполагаю, что ваш пример имеет дело) определяется реализацией.
Ответ 3
В С++ нет. Это зависит от реализации и/или платформы.
В некоторых других языках да. Например, в Java оператор → точно определяется так, что он всегда заполняется левым самым битом (тем самым сохраняя знак). Оператор → > заполняется с использованием 0s. Поэтому, если вы хотите надежного поведения, одним из возможных вариантов будет переход на другой язык. (Хотя, очевидно, это может быть не вариант в зависимости от ваших обстоятельств.)
Ответ 4
Целые числа AFAIK могут быть представлены как знак-величина в С++, и в этом случае расширение знака будет заполняться 0s. Поэтому вы не можете полагаться на это.
Ответ 5
Из последней версии С++ 20:
Сдвиг вправо на целочисленных типах со знаком является арифметическим сдвигом вправо, который выполняет расширение знака.