Я хочу прочитать 4 байта, которые являются порядком байтов с прямым порядком байтов 32-разрядного целого числа без знака, и присвоить значение Java int
(Да, на самом деле я буду использовать «long», но в этом случае я «знаю», что значение без знака никогда не бывает таким большим, что оно будет переполнено знаком int в нотации дополнения до двух, и это подходит для моей иллюстрации используйте int).
4 байта, о которых идет речь, кодируют значение 216 в стиле little-endian:
0xD8000000
И в основном мне просто нужно вставить следующий битовый шаблон в Java int:
0x000000D8
Следующий простой код должен это сделать ... и для первых трех байтов «0x00» это успешно выполняется:
byte b1 = din.readByte();
byte b2 = din.readByte();
byte b3 = din.readByte();
byte b4 = din.readByte();
int s = 0;
s = s | b4;
s = (s << 8);
s = s | b3;
s = (s << 8);
s = s | b2;
s = (s << 8);
s = s | b1;
return s;
Однако, он облажается:
s = s | b1;
... потому что биты b1 равны 1101 1000, что является отрицательным числом (-40) в двоичной нотации, поскольку наиболее значимый бит равен 1. Когда Java расширяет b1 до целого числа перед оценкой побитового значения или оператор |, -40 кодируется как 0xFFFFFFD8, что порождает наше наивное предположение, что первые 3 байта расширенного целого будут 0.
Так что моя стратегия на мель. Но что мне делать вместо этого? Возможно ли даже решить эту проблему с помощью примитивных операторов (просьба дать решение), или мы должны прибегнуть к библиотеке классов? (Я не слишком много играю с битами и байтами напрямую в моем обычном кодировании, поэтому мне не хватает идиомы для того, что должно быть «повседневным» кодом).
Что касается подхода к библиотеке классов, следующий фрагмент дает правильный результат:
ByteBuffer b = ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).put((byte) 0xD8).put((byte) 0x00).put((byte) 0x00).put((byte) 0x00);
b.flip();
int s = b.getInt();
... что хорошо для удобочитаемости, но использует 8 вызовов методов, с которыми я бы лучше обошелся.
спасибо!
Дэвид.