Bitshift и целое продвижение?
Обычно C требует, чтобы бинарные операнды операторов продвигались к типу операнда более высокого ранжирования. Это можно использовать, чтобы избежать заполнения кода с помощью verbose casts, например:
if (x-48U<10) ...
y = x+0ULL << 40;
и др.
Однако я обнаружил, что, по крайней мере, с gcc, это поведение не работает для бит-сдвигов. То есть.
int x = 1;
unsigned long long y = x << 32ULL;
Я бы ожидал, что тип правого операнда приведет к тому, что левый операнд будет продвинут на unsigned long long
, чтобы сдвиг был успешным. Но вместо этого gcc печатает предупреждение:
warning: left shift count >= width of type
Является ли gcc сломанным, или стандарт делает какое-то исключение для правил продвижения типов для бит-брейков?
Ответы
Ответ 1
Так называемые обычные арифметические преобразования применяются ко многим бинарным операторам, но не ко всем из них. Например, они не применяются к операторам сдвига битов, операторам amp;, ||, запятой и операторам присваивания. Это правило для операторов сдвига бит:
6.5.7... 3 Семантика...
Целочисленные рекламные акции выполняются на каждом из операндов. Тип результата - это продвинутый левый операнд. Если значение правильного операнда отрицательное или больше или равно ширине продвинутого левого операнда, поведение undefined.
Ответ 2
Беда в том, что продвижение по службе работает только до того, что ваша платформа определяет как int
. Как уже говорили некоторые другие ответы, оператор бит-сдвига будет продвигать левый операнд в int. Однако здесь int
определяется как 32-битное значение. Целочисленное преобразование не будет распространяться на long long
(64-разрядный).
Ответ 3
Вот что я нашел на эту тему:
- Операторы побитового сдвига перемещают битовые значения двоичного объекта.
- Левый операнд указывает значение, которое должно быть смещено.
- Правый операнд определяет количество позиций, на которые биты в значении должны быть сдвинуты.
- Результат не lvalue.
Оба операнда имеют одинаковый приоритет и являются ассоциативными слева направо. Каждый операнд должен иметь тип целого или перечисления. Компилятор выполняет интегральное продвижение над операндами, а затем правый операнд преобразуется в тип int. Результат имеет тот же тип, что и левый операнд (после арифметических преобразований).
Правый операнд не должен иметь отрицательного значения или значения, которое больше или равно ширине в битах смещаемого выражения. Результат побитовых сдвигов на таких значениях непредсказуем.
Если правый операнд имеет значение 0, результатом является значение левого операнда (после обычных арифметических преобразований). Оператор << заполняет освобожденные биты нулями.
Например, если left_op
имеет значение 4019
, битовая комбинация (в 16-битном формате) left_op
имеет вид:
0000111110110011
Выражение left_op << 3 дает:
0111110110011000
Выражение left_op >> 3 дает:
0000000111110110
Источник: https://www.ibm.com/support/knowledgecenter/en/SSLTBW_2.3.0/com.ibm.zos.v2r3.cbclx01/bitshe.htm