Что делать, если в операторах сдвига используется оператор приведения

В JLS говорится, что

Тип выражения сдвига - это расширенный тип левого операнда.

Если повышенным типом левого операнда является int, то в качестве расстояния сдвига используются только пять младших битов правого операнда. Это как если бы правый операнд был подвергнут поразрядному логическому оператору AND & (§15.22.1) со значением маски 0x1f (0b11111). Таким образом, фактически используемое расстояние сдвига всегда находится в диапазоне от 0 до 31 включительно.

Если расширенный тип левого операнда длинный, то в качестве расстояния сдвига используются только шесть младших битов правого операнда. Это как если бы правый операнд был подвергнут побитовой логической операции AND & (§15.22.1) со значением маски 0x3f (0b111111). Таким образом, фактически используемое расстояние сдвига всегда находится в диапазоне от 0 до 63 включительно.

Итак, если я явно сделаю байт и короткий операнд с помощью оператора приведения, такого как (byte)100<<100 и (short)100<<100, какие биты правильного операнда будут использоваться?

Изменить: подвергается ли операнд числовому продвижению (унарный / двоичный), если он уже был преобразован в другой (меньший) тип с помощью оператора литья? Если это так, как бы вы объяснили выражение, имеющее байтовые переменные b1 = (byte)(b2 + b3), потому что после преобразования приведения результат в байтах, вероятно, будет преобразован в int согласно числовому продвижению?


person user12208242    schedule 18.08.2020    source источник


Ответы (2)


В Java 8 JLS также говорится в §5.6.1:

5.6.1. Унарное числовое продвижение

Некоторые операторы применяют унарное числовое продвижение к одному операнду, который должен давать значение числового типа:

...

  • В противном случае, если операнд имеет тип времени компиляции byte, short или char, он повышается до значения типа int расширяющимся примитивным преобразованием (§5.1.2).

...

Таким образом, если взять следующее выражение:

int i = ...
short s = (short) i << 2;

Приведет к ошибке компилятора:

Main.java:4: error: incompatible types: possible lossy conversion from int to short
short s = (short) i << 2;

Демонстрация Ideone

Это связано с тем, что приведение типов привязывается к первому аргументу сдвига, а не ко всему выражению. Вот полное выражение с явными скобками:

short s = ((byte) i) << 2;

В то время как

int i = ...;
int j = (short) i << 2;

Будет успешно компилироваться.

Демонстрация Ideone

Таким образом, эффективные биты, которые нужно использовать для чего-либо < int, такие же, как и для int (5 битов), поскольку они автоматически повышаются до int.

Если вы приведете результат всего выражения к, например, short (short s = (short) (i << 2), тогда в компиляторе нет автоматизма. Но Богемский ответ дает логическую оценку того, что биты правого оператора будут эффективно влиять на значение после приведения.


В более новых версиях JLS раздел был изменен. Например, в Java 14 JLS, §5.6 мы находим (раздел сокращен для краткости, я рекомендую прочитать весь абзац, чтобы получить полный контекст):

5.6. Числовые контексты

Числовые контексты применяются к операндам арифметических операторов, выражениям создания массивов и доступа к ним, условным выражениям и выражениям результатов выражений переключения.

Выражение появляется в числовом арифметическом контексте, если выражение является одним из следующих:

...

  • Операнд оператора сдвига <<, >> или >>> (§15.19). Операнды этих операторов сдвига рассматриваются отдельно, а не как группа. Расстояние сдвига long (правый операнд) не способствует сдвигу значения (левый операнд) на long.

...

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

...

  1. Затем расширяющееся примитивное преобразование (§5.1.2) и сужающее примитивное преобразование (§5.1.3) применяются к некоторым выражениям в соответствии со следующими правилами:

    ...

    • В противном случае ни одно из выражений не относится к типу double, float или long. В этом случае вид контекста определяет, как будет выбран продвигаемый тип.

      В числовом арифметическом контексте или контексте числового массива повышенным типом является int, а любые выражения, не принадлежащие к типу int, подвергаются расширяющему примитивному преобразованию в int.

      В контексте числового выбора применяются следующие правила:

      ...

      • Otherwise, the promoted type is int, and all the expressions that are not of type int undergo widening primitive conversion to int.

      ...

person Turing85    schedule 18.08.2020
comment
Значит ли это, что даже если я делаю (коротко) 100, на самом деле это будет int 100? - person user12208242; 18.08.2020
comment
Это не пытается ответить на вопрос, который спрашивает, какие будут использоваться биты правого операнда (а не какой тип результата) - person Bohemian♦; 18.08.2020
comment
Нет, если вы приводите переменную, она имеет приведенный тип. Проблема, однако, в том, что приведенное значение затем используется в бинарной числовой операции. Чтобы быть более точным: выражение, которое вы опубликовали с явными скобками, - ((short) 100) << 100. Вы имели в виду (short) (100 << 100)? - person Turing85; 18.08.2020
comment
@ Turing85 Я получил ссылку, в которой говорится, что это не двоичная числовая операция, а унарная. notendur.hi.is/snorri/SDK-docs/lang/. - person user12208242; 18.08.2020
comment
@ user12208242 Я обновил свой ответ и пояснил, что на самом деле приводит актерский состав. Надеюсь, это поможет =) Я также обновил раздел JLS, чтобы отразить унарный оператор как в JLS 8, так и в JLS 14 - person Turing85; 18.08.2020
comment
Если вы установите приведение всего выражения к, например, short (short s = (short) (i ‹< 2), то в компиляторе нет автоматизма. Но даже если вы приведете все выражение к short (short) (i ‹< 2), ваш короткий результат преобразует результат в int в соответствии с числовым продвижением. Это, в свою очередь, должно привести к ошибке. Так это какое-то исключение, когда продвижение не выполняется или что-то в этом роде? Похоже, я погрузился в другой вопрос. - person user12208242; 18.08.2020
comment
@ user12208242 Давайте продолжим обсуждение в чате? - person Turing85; 18.08.2020

Количество битов максимального используемого расстояния сдвига определяется как log 2 n, где n - количество битов, используемых для представления значений левого типа.

byte имеет 8 бит. log 2 8 равно 3. Таким образом, используются только самые правые 3 бита, что дает значение сдвига в диапазоне 0-7.

short имеет 16 бит. log 2 16 равно 4. Таким образом, используются только самые правые 4 бита, что дает значение сдвига в диапазоне 0-15.

person Bohemian♦    schedule 18.08.2020
comment
Хотя это технически верно, выражение, данное в вопросе, всегда будет давать ints, поскольку типы < int расширяются до ints. - person Turing85; 18.08.2020
comment
@ Turing85 вопрос не спрашивает, что такое результирующий тип. В вопросе задается вопрос: какие части правильного операнда будут использоваться. - person Bohemian♦; 18.08.2020
comment
Это не совсем так. левый операнд расширяется до int. Таким образом, правый операнд ограничен пределом int. - person Turing85; 18.08.2020
comment
@ Turing85 тип правого операнда не имеет значения. Это о том, сколько битов этого операнда используется. - person Bohemian♦; 18.08.2020
comment
... и это - в свою очередь - зависит от типа операнда left, который повышается до int. - person Turing85; 18.08.2020
comment
@ Turing85, вы здесь совершенно не понимаете. Тип правого операнда значения не имеет. Тип левого операнда определяет, сколько битов правого операнда используется независимо от его типа. Вопрос только спрашивает сколько битов правого операнда можно использовать. - person Bohemian♦; 18.08.2020
comment
Я хочу сказать, что тип оператора левой для всего< int - int и, таким образом, поведение определяется в JLS как 5 бит =) - person Turing85; 18.08.2020