Сдвиг вправо и целое число со знаком - PullRequest
17 голосов
/ 23 сентября 2011

На моем компиляторе следующий псевдокод (значения заменены на двоичные):

sint32 word = (10000000 00000000 00000000 00000000);
word >>= 16;

создает word с битовым полем, которое выглядит следующим образом:

(11111111 11111111 10000000 00000000)

У меня вопрос: могу ли я полагаться на это поведение для всех платформ и компиляторов C ++?

Ответы [ 5 ]

23 голосов
/ 23 сентября 2011

По следующей ссылке:
INT34-C. Не сдвигайте выражение на отрицательное число битов или больше или равно количеству битов, имеющихся в операнде

Пример несовместимого кода (сдвиг вправо)
Результат E1 >> E2 равен E1 смещенным вправо E2 позициям битов. Если E1 имеет тип без знака или E1 имеет тип со знаком и неотрицательное значение, значение результата является неотъемлемой частью отношения E1 / 2 E2 . Если E1 имеет тип со знаком и отрицательное значение, полученное значение определяется реализацией и может быть арифметическим (подписанным) сдвигом:
Arithmetic (signed) shift
или логическое (без знака) смещение:
Logical (unsigned) shift
Этот пример несовместимого кода не в состоянии проверить, больше ли правый операнд или равен ширине повышенного левого операнда, что допускает неопределенное поведение.

unsigned int ui1;
unsigned int ui2;
unsigned int uresult;

/* Initialize ui1 and ui2 */

uresult = ui1 >> ui2;

Создание предположений о том, реализован ли сдвиг вправо как арифметический (подписанный) сдвиг или логический (беззнаковый) сдвиг, также может привести к уязвимости. См. Рекомендацию INT13-C. Используйте побитовые операторы только для беззнаковых операндов .

13 голосов
/ 23 сентября 2011

Нет, вы не можете полагаться на это поведение.Сдвиг вправо отрицательных величин (которые, как я предполагаю, имеет в виду ваш пример) определяется реализацией.

6 голосов
/ 23 сентября 2011

В C ++ нет.Это зависит от реализации и / или платформы.

В некоторых других языках, да.В Java, например, оператор >> точно определен, чтобы всегда заполнять, используя самый левый бит (тем самым сохраняя знак).Оператор >>> заполняется с использованием 0s.Так что, если вам нужно надежное поведение, одним из возможных вариантов будет переход на другой язык.(Хотя, очевидно, это не может быть вариантом в зависимости от ваших обстоятельств.)

3 голосов
/ 23 сентября 2011

Целые числа AFAIK могут быть представлены как знак-величина в c ++, и в этом случае расширение знака будет заполняться нулями.Так что на это нельзя полагаться.

1 голос
/ 01 февраля 2019

Из последней версии C ++ 20 :

Сдвиг вправо на целочисленных типах со знаком - это арифметическое смещение вправо, которое выполняет расширение знака.

...