При смещении влево можно установить номер в ноль - PullRequest
4 голосов
/ 24 февраля 2012

У меня есть сомнения в операторе левого сдвига

int i = 1;
i <<= (sizeof (int) *8);
cout << i;

Он печатает 1.

  1. я был инициализирован в 1.
  2. И, перемещая биты до размера целого числа, он заполняет младший бит нулями, а когда 1 пересекает предел целого числа, я ожидал, что на выходе будет 0.

Как и почему это 1?

Ответы [ 4 ]

14 голосов
/ 24 февраля 2012

Допустим, sizeof(int) - это 4 на вашей платформе.Тогда выражение становится:

i = i << 32;

Стандарт гласит:

6.5.7-3

Если значение правого операнда отрицательно или равно больше или равно ширине повышенного левого операнда , поведение не определено.

3 голосов
/ 24 февраля 2012

Как сказал cnicutar , ваш пример демонстрирует неопределенное поведение.Это означает, что компилятор может делать все, что ему кажется подходящим, в том числе заставлять демонов выскакивать из носа или просто ничего не делать с имеющимся значением.

Что вы можете сделать, чтобы убедить себя, что сдвиг влево на количество битов даст 0 это:

int i = 1;
i <<= (sizeof (int) *4);
i <<= (sizeof (int) *4);
cout << i;
2 голосов
/ 24 февраля 2012

Расширение до предыдущего ответа ...

На платформе x86 ваш код будет скомпилирован примерно так:

; 32-bit ints:
mov cl, 32
shl dword ptr i, cl

Процессор будетсдвиньте слово в переменной i на значение, содержащееся в регистре cl по модулю 32. Таким образом, 32 по модулю 32 дает 0. Следовательно, сдвиг на самом деле не происходит.И это прекрасно в соответствии со стандартом C.Фактически, то, что стандарт C говорит в 6.5.7-3, заключается в том, что вышеупомянутое поведение ЦП было довольно распространено в те времена и влияло на стандарт.

1 голос
/ 24 февраля 2012

Как уже упоминалось другими, согласно стандарту C поведение сдвига не определено.

Тем не менее, программа печатает 1. Низкоуровневое объяснение того, почему она печатает 1, выглядит следующим образом:

При компиляции без оптимизации компилятор (GCC, clang) выдает инструкцию SHL:

...
mov    $32,%ecx
shll   %cl,0x1c(%esp)
...

Документация Intel для SHL инструкции гласит:

SAL / SAR / SHL / SHR-Shift

Счет маскируется до 5 бит (или 6 бит, если в 64-битном режиме используется REX.W). Диапазон счетчиков ограничен от 0 до 31 (или 63, если используется 64-битный режим и REX.W).

Маскирование счетчика сдвига 32 (двоичный код 00100000) до 5 битов дает 0 (двоичный код 00000000). Поэтому инструкция shll %cl,0x1c(%esp) не выполняет никакого смещения и оставляет значение i без изменений.

...