Обратная операция сдвига байтов - PullRequest
4 голосов
/ 30 ноября 2011

У меня есть этот код

byte[] b = new byte[]{-33,-4,20,30};
System.err.println(Arrays.toString(b));

int x =  (b[0] << 24) + (b[1] << 16) + (b[2] << 8) + b[3];

b = new byte[]{(byte)(x >> 24), (byte)(x >> 16), (byte)(x >> 8), (byte)(x)};

System.err.println(Arrays.toString(b));

Вывод:

[-33, -4, 20, 30]
[-34, -4, 20, 30]

Я не могу понять, почему эти операции не являются инверсиями.

Ответы [ 2 ]

6 голосов
/ 30 ноября 2011

Ваша проблема связана с нежелательным расширением знака.

В частности, b[1] равно -4 или 0xfc, которое расширено до 0xfffffffc, а затем смещено влево до 0xfffc0000.Это приводит к уменьшению старшего значащего байта на 1.

Попробуйте:

int x =  ((b[0] & 0xff) << 24) +
         ((b[1] & 0xff) << 16) +
         ((b[2] & 0xff) << 8) +
          (b[3] & 0xff);
3 голосов
/ 30 ноября 2011

Пожалуйста, не обращайте внимания на мой предыдущий ответ;это абсолютно неправильно.

Я думаю, что проблема здесь в том, что когда вы составляете биты таким образом:

(b[0] << 24) + (b[1] << 16) + (b[2] << 8) + b[3]

Вы не делаете то, что вы думаете, что выделаешь.В частности, предположим, что b[1] отрицательно (что это такое).Когда Java выполняет битовые сдвиги, она всегда переводит значение в int перед выполнением сдвига.Это означает, что b[1] будет выглядеть следующим образом при продвижении по службе:

11111111 11111111 11111111 bbbbbbbb

Здесь первые 1 взяты из представления целых чисел со знаком дополнения до двух, что делает отрицательные числа, представленные множеством ведущихнули.Когда вы сдвигаете это число вверх, вы получите

11111111 bbbbbbbb 00000000 00000000

Если вы затем добавите эти биты к (b[0] << 24), который имеет вид

aaaaaaaa 00000000 00000000 00000000

Вы делаете не get

aaaaaaaa bbbbbbbb 00000000 00000000

Из-за первых 1 в представлении.Чтобы это исправить, вам нужно замаскировать биты знака перед выполнением сложения.В частности, если вы измените

b[1] << 16

на

(b[1] << 16) & 0x00FFFFFF

Затем вы замаскируете биты, чтобы получить

00000000 bbbbbbbb 00000000 00000000

Так что теперь, когда вы добавляете два значения,вы получите

aaaaaaaa bbbbbbbb 00000000 00000000

По желанию.

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

(b[0] << 24) + ((b[1] << 16) & 0x00FFFFFF) + ((b[2] << 8) & 0x0000FFFF) + (b[3] & 0x000000FF)

IЯ проверил это на моей системе, и, похоже, он работает нормально.

Надеюсь, это поможет!

...