Читает ли Java целые числа с прямым или обратным порядком байтов?


96

Я спрашиваю, потому что отправляю поток байтов из процесса C в Java. На стороне C 32-битное целое число имеет LSB - это первый байт, а MSB - это 4-й байт.

Итак, мой вопрос: на стороне Java, когда мы читаем байт, который был отправлен из процесса C, что такое порядок байтов на стороне Java?

Последующий вопрос: если порядок байтов на стороне Java не совпадает с отправленным, как я могу конвертировать между ними?


2
Вот моя мнемоника, поэтому я не забуду: Java - это не аппаратное обеспечение, а виртуальный язык, это язык Интернета. Сетевой порядок байт являются большими байтами . Следовательно, Java является прямым порядком байтов .
eigenfield

Ответы:


67

Используйте сетевой порядок байтов (прямой порядок байтов), который в любом случае такой же, как и в Java. См. Man htons для различных переводчиков в C.


Я сейчас не в своем Linux-боксе, но является ли htons одной из стандартных библиотек?
hhafez

Согласно h30097.www3.hp.com/docs//base_doc/DOCUMENTATION/V51_HTML/MAN/… это часть стандартной библиотеки c, да
Эгиль

1
htons доступен почти везде, но не в ISO C.
MSalters

1
Если вам нужно использовать что-то другое, кроме сетевого порядка байтов, то вы либо используете свои собственные побитовые операторы, либо используете различные версии java.nio.Buffer
Даррон

1
Согласно его справочной странице, он определен в POSIX.1, поэтому он должен быть доступен практически везде. И я, кажется, помню, как использовал его в Win32, так что он не только в системах POSIX.
Иоахим Зауэр,

50

Я наткнулся здесь через Google и получил ответ, что Java является прямым порядком байтов .

Читая ответы, я хотел бы отметить, что байты действительно имеют порядок следования байтов, хотя, к счастью, если вы имели дело только с «массовыми» микропроцессорами, вы вряд ли когда-либо сталкивались с этим, поскольку Intel, Motorola и Zilog все согласились с направлением сдвига своих микросхем UART и что MSB байта будет, 2**7а LSB будет 2**0в их процессорах (я использовал обозначение мощности FORTRAN, чтобы подчеркнуть, сколько лет этому материалу :)).

Я столкнулся с этой проблемой с некоторыми последовательными данными нисходящего канала Space Shuttle более 20 лет назад, когда мы заменили интерфейсное оборудование стоимостью 10 тысяч долларов на компьютер Mac. Об этом давно опубликован доклад NASA Tech. Я просто использовал поисковую таблицу из 256 элементов с перевернутыми битами ( table[0x01]=0x80и т. Д.) После того, как каждый байт был сдвинут из потока битов.


Отличное понимание! У меня есть этот вопрос и нет ответов в сети.
Xolve

если какие-то из них будут общедоступными, не могли бы вы связать технический отчет НАСА (и, возможно, последовательные данные нисходящей линии связи космических челноков), о которых вы говорите? было бы интересно, я никогда не видел ничего подобного.
n611x007 08

3
Побитовый порядок байтов также играет роль с форматами сжатия, которые используют некоторую форму кодирования Хаффмана (то есть все они). Для дополнительного развлечения, JPEG является "побитовым прямым порядком байтов" (т. Е. Наиболее значимый бит - это "первый" бит), а LZ - "побитовым прямым порядком байтов". Однажды я работал над проприетарным форматом сжатия, который использовал оба формата под капотом. О, это было весело ...
user435779 05

Начав с битов, я долгое время думал, что ЭТО БУДЕТ.
Рой Фальк,

20

В Java нет целых чисел без знака. Все целые числа подписаны и имеют прямой порядок байтов.

На стороне C каждый байт имеет младший бит в начале слева и старший бит в конце.

Похоже, вы используете LSB как младший бит, не так ли? LSB обычно обозначает младший байт. Порядок байтов основан не на битах, а на байтах.

Чтобы преобразовать из байта без знака в целое число Java:

int i = (int) b & 0xFF;

Чтобы преобразовать из беззнакового 32-битного little-endian в byte [] в Java long (из верхней части моей головы, не тестировалось):

long l = (long)b[0] & 0xFF;
l += ((long)b[1] & 0xFF) << 8;
l += ((long)b[2] & 0xFF) << 16;
l += ((long)b[3] & 0xFF) << 24;

только что понял, что: $ Итак, как я должен отправить этот неподписанный маленький порядок байтов в мой Java-процесс, чтобы его правильно прочитать?
hhafez

Что я имею в виду под началом, это то, что lsb находится в начале 4 байтов (это 32-битное
целое

Также я конвертирую из C -> Java, а не из Java -> C :)
hhafez

Ваш код работает нормально, если вы удалите точку с запятой после 0xFF в последних трех строках. Я бы отредактировал это сам, но это изменение менее 6 символов.
Moose Morals

1
Прошло почти 8 лет, но наконец кто-то заметил синтаксическую ошибку. Спасибо @MooseMorals :)
Jonas Elfström 04

12

Это никак не может повлиять на что-либо в Java, поскольку в Java нет способа (прямого, не связанного с API) отображать некоторые байты непосредственно в int.

Каждый API, который делает это или что-то подобное, довольно точно определяет поведение, поэтому вам следует поискать документацию по этому API.


3
Конечно, есть. Двоичная математика (&, |, << и т. Д.) Отлично работает с байтами и целыми числами. Достаточно легко взять произвольные байты и вставить их в целое число.
Herms

8
Но если вы сделаете это, вы все равно не сможете определить, какой порядок байтов использует ваша JVM для внутренних целей.
Darron

4
Да, но даже там вы напрямую не сопоставляете. Вы используете арифметику, которая делает именно то, что вы ей говорите, нет двусмысленности. В C вы всегда можете преобразовать «byte *» в «long *» и отменить ссылку на него. Тогда вам придется позаботиться о порядке байтов. В Java нет прямого двусмысленного способа сделать это.
Иоахим Зауэр,

Ах я вижу. Вы говорили о актерском составе, а не о двоичной математике. Да, в таком случае ты прав.
Herms,

10
+1 за «поиск документации», но ПРИМЕЧАНИЕ: 1-е предложение уже неверно, так как в настоящее время пакет NIO предлагает ByteBuffer, который может отображать байты в примитивы, и где вы можете изменить порядок байтов. См. ByteBuffer и ByteOrder
user85421

3

Я читал байты один за другим и объединял их в длинное значение. Таким образом, вы контролируете порядок байтов, и процесс коммуникации становится прозрачным.


Не хотите прокомментировать, почему вы голосуете за меня?
Воутер Ливенс,

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

23
Порядок байтов в байтах? Что это за фигня? Слова чувствительны к порядку байтов, отдельные байты - нет.
Воутер Ливенс,

3
@hhafez Это неправда, байты не имеют порядка байтов, насколько нам нужно беспокоиться, если вы читаете побайт за байтом, вы, программист, несете ответственность за назначение байтов в нужное место. Именно это и делает DataInputStream: он просто собирает байты вместе с прямым порядком байтов под капотами.

2
@WouterLievens: Я встречал некоторые устройства ввода-вывода (например, микросхему часов реального времени), которые по какой-либо причине отправляют данные в формате с инвертированием битов; после получения от них данных необходимо поменять местами биты в каждом байте. Однако я согласен с вами в том, что порядок байтов в байтах обычно не является проблемой, если только не приходится иметь дело с конкретными аппаратными средствами странной конструкции.
supercat

3

Если он соответствует используемому вами протоколу, рассмотрите возможность использования DataInputStream, где поведение очень хорошо определено .


1
Он может сделать это только в том случае, если в его протоколе используется такой же порядок байтов.
Воутер Ливенс,

Я исправил ссылку и изменил ее на Java 9, текущую версию. Однако рассматриваемый API был представлен в Java 1.0.
Йенс Баннманн

2

Как отмечалось выше, Java имеет "обратный порядок байтов". Это означает, что MSB int находится слева, если вы исследуете память (по крайней мере, на процессоре Intel). Знаковый бит также находится в MSB для всех целочисленных типов Java.
Чтение 4-байтового беззнакового целого числа из двоичного файла, хранящегося в системе с прямым порядком байтов, требует некоторой адаптации в Java. ReadInt () DataInputStream ожидает формат с прямым порядком байтов.
Вот пример, который считывает четырехбайтовое беззнаковое значение (как показано HexEdit как 01 00 00 00) в целое число со значением 1:

 // Declare an array of 4 shorts to hold the four unsigned bytes
 short[] tempShort = new short[4];
 for (int b = 0; b < 4; b++) {
    tempShort[b] = (short)dIStream.readUnsignedByte();           
 }
 int curVal = convToInt(tempShort);

 // Pass an array of four shorts which convert from LSB first 
 public int convToInt(short[] sb)
 {
   int answer = sb[0];
   answer += sb[1] << 8;
   answer += sb[2] << 16;
   answer += sb[3] << 24;
   return answer;        
 }

Что означает «отмеченное выше»? Порядок отображения ответов SO может варьироваться.
Ларш

0

java force действительно big endian: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.11


3
Это касается порядка байтов инструкций байт-кода, а не порядка байтов данных во время выполнения.
kaya3 04

Я голосую. Этот фрагмент byte[] bbb = ByteBuffer.allocate(4).putFloat(0.42f).array();создал byteмассив, противоположный тому, что было C/C++создано мной . Следовательно, обратный порядок байтов Java действует даже в данных во время выполнения.
eigenfield
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.