Предупреждение Findbugs: целочисленный сдвиг на 32, что это значит?

Я сканировал сторонний исходный код с помощью Findbugs (просто чтобы быть осторожным, прежде чем интегрировать в него свой) и обнаружил следующее предупреждение:

long a = b << 32 | c

Ошибка: целочисленный сдвиг на 32. Идентификатор шаблона: ICAST_BAD_SHIFT_AMOUNT, тип: BSHIFT, категория: ПРАВИЛЬНОСТЬ.

Код выполняет целочисленный сдвиг на постоянную величину за пределами диапазона 0..31. Результатом этого является использование младших 5 битов целочисленного значения, чтобы решить, на сколько сдвигать. Это, вероятно, не то, что ожидалось, и это, по крайней мере, сбивает с толку.

Может ли кто-нибудь объяснить, что именно означает вышеизложенное?

Спасибо! (Я совсем новичок в программировании на Java)


person His    schedule 21.06.2009    source источник


Ответы (2)


Из Спецификации языка Java:

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

Итак, если b является целым числом, выражение идентично

long a = b | c;

что я очень сомневаюсь, что это то, что предназначено. Вероятно, это должно было быть

long a = ((long) b << 32) | c;

(Если b уже длинное, код правильный и FindBugs ошибается).

person Rasmus Faber    schedule 21.06.2009
comment
Странный у вас псевдосинтаксис, но да, это так. - person UndefinedBehavior; 02.10.2014

Отредактировано: Проблема почти наверняка связана с тем, что "b" - это "int", а не "long".

В C, если 'b' является целым числом, а не длинным, и вы выполняете сдвиг влево на 32 бита, все биты исходного значения удаляются, поэтому результат общего выражения будет таким же, как 'c ' вы вызовете неопределенное поведение, поэтому допустим любой результат. Java определяет вещи по-другому - как отмечено в комментарии Расмуса Фабера и выбранном ответе - и делает сверхдлинные сдвиги по модулю максимального количества битов, которые можно сдвинуть. [Это кажется странным способом ведения бизнеса; Я бы, наверное, устроил исключение для языка, в котором они есть. Однако оно четко определено, что более важно, чем точное определение.] Приведение к 64-битам не происходит во время вычисления выражения; это происходит, когда выражение завершено и происходит присваивание.

Ссылка на 5 бит... интригует. Это означает, что сдвиг влево, скажем, на 48 или двоичное число 110000 будет таким же, как сдвиг влево на 16. Или, альтернативно, 'x << n' будет таким же, как 'x << (n % 32)'.

person Jonathan Leffler    schedule 21.06.2009
comment
Первая часть вашего ответа неверна. В Jave b ‹‹ 32 — это b, а не ноль. Однако второй параграх верен. - person Rasmus Faber; 21.06.2009
comment
Исправление: в C поведение undefined при смещении значения с аргументом вне диапазона [0, typewidth - 1]. Например, компиляторы opencl от nvidia и intel дают мне различное поведение для выражения «b ›› 32». - person notso; 15.10.2012
comment
та же проблема с <long> << 64 :( - person Jake Biesinger; 18.12.2013