Подтвердить что ты не робот

Поведение без знакового сдвига вправо для байтовой переменной

Рассмотрим следующий снимок java-кода

byte b=(byte) 0xf1;
byte c=(byte)(b>>4);
byte d=(byte) (b>>>4);

выход:

c=0xff
d=0xff

ожидаемый вывод:

c=0x0f

как? как b в двоичном 1111 0001 после беззнакового сдвига вправо 0000 1111 следовательно 0x0f, но почему это 0xff как?

4b9b3361

Ответ 1

Проблема заключается в том, что перед началом операции сдвига все аргументы сначала продвигаются до int:

byte b = (byte) 0xf1;

b, поэтому его значение равно -15.

byte c = (byte) (b >> 4);

b сначала расшифровывается знаком до целого числа -15 = 0xfffffff1, а затем сдвигается вправо до 0xffffffff и усекается до 0xff приложением byte.

byte d = (byte) (b >>> 4);

b сначала расшифровывается знаком до целого числа -15 = 0xfffffff1, а затем сдвигается вправо до 0x0fffffff и усекается до 0xff приложением byte.

Вы можете сделать (b & 0xff) >>> 4, чтобы получить желаемый эффект.

Ответ 2

Догадываюсь, что перед изменением знак b будет расширен до int.

Итак, это может сработать так, как ожидалось:

(byte)((0x000000FF & b)>>4)

Ответ 3

В соответствии с Побитовые и операторы сдвига бит:

Беззнаковый оператор сдвига вправо " → > " сдвигает нуль в крайнее левое положение, а крайняя левая позиция после " → " зависит от расширения знака.

Итак, с b >> 4 вы преобразуете 1111 0001 в 1111 1111 (b отрицательно, поэтому он добавляет 1), который равен 0xff.

Ответ 4

Java пытается сэкономить на явной поддержке базовых типов без знака, вместо этого определяя два разных оператора сдвига.

В этом вопросе речь идет о беззнаковом сдвиге справа, но в примерах используются как (подписанные, так и неподписанные) и отображается значение подписанного сдвига ( → ).

Ваши вычисления были бы правильными для беззнакового сдвига ( → > ).