¿Java lee enteros en little endian o big endian?

94

Lo pregunto porque estoy enviando un flujo de bytes desde un proceso C a Java. En el lado C, el entero de 32 bits tiene el LSB es el primer byte y el MSB es el cuarto byte.

Entonces mi pregunta es: en el lado de Java cuando leemos el byte tal como fue enviado desde el proceso C, ¿qué es endian en el lado de Java?

Una pregunta de seguimiento: si el endian en el lado de Java no es el mismo que el enviado, ¿cómo puedo convertir entre ellos?

hhafez
fuente
1
Aquí están mis nemotécnicos para esto, así que no lo olvidaré: Java, al no ser hardware sino virtual, es el lenguaje de Internet. El orden de bytes de la red es big endian . Por lo tanto, Java es big endian .
Truthadjustr

Respuestas:

66

Utilice el orden de bytes de la red (big endian), que es el mismo que utiliza Java de todos modos. Vea man htons para los diferentes traductores en C.

Egil
fuente
No estoy en mi caja de Linux ahora, pero ¿htons es una de las librerías estándar?
hhafez
De acuerdo con h30097.www3.hp.com/docs//base_doc/DOCUMENTATION/V51_HTML/MAN/… es parte de la biblioteca c estándar, sí
Egil
1
htons está disponible en casi todas partes, pero no en ISO C.
MSalters
1
Si tiene que usar algo que no sea el orden de bytes de la red, entonces puede usar el suyo con operadores bit a bit o usar las diversas versiones de java.nio.Buffer
Darron
1
Según su página de manual, está definido en POSIX.1, por lo que debería estar disponible prácticamente en todas partes. Y creo recordar haberlo usado en Win32, por lo que tampoco es solo en sistemas POSIX.
Joachim Sauer
47

Encontré aquí a través de Google y obtuve mi respuesta de que Java es big endian .

Al leer las respuestas, me gustaría señalar que los bytes tienen un orden endian, aunque afortunadamente, si solo ha tratado con microprocesadores "convencionales", es poco probable que lo haya encontrado alguna vez como Intel, Motorola y Zilog. acordó la dirección de cambio de sus chips UART y que MSB de un byte sería 2**7y LSB estaría 2**0en sus CPU (usé la notación de potencia FORTRAN para enfatizar la antigüedad de estas cosas :)).

Me encontré con este problema con algunos datos de enlace descendente en serie de bits del transbordador espacial hace más de 20 años cuando reemplazamos un hardware de interfaz de $ 10K con una computadora Mac. Hay un informe técnico de la NASA publicado al respecto hace mucho tiempo. Simplemente utilicé una tabla de búsqueda de 256 elementos con los bits invertidos ( table[0x01]=0x80etc.) después de que cada byte se cambiara del flujo de bits.

WB Greene
fuente
¡Gran conocimiento! Tengo esta pregunta y no tengo respuestas en la web.
Xolve
si alguno de ellos es público, ¿podría vincular el informe técnico de la NASA (y quizás los datos del enlace descendente en serie del bit del transbordador espacial) del que está hablando? sería fascinante, nunca había visto una cosa así.
n611x007
3
El endianness bit a bit también entra en juego con los formatos de compresión que usan alguna forma de codificación Huffman (es decir, todos). Para mayor diversión, JPEG es "big-endian bit a bit" (es decir, el bit más significativo es el "primer" bit) y LZ es "little-endian bit a bit". Una vez trabajé en un formato de compresión patentado que usaba ambos formatos bajo el capó. Oh, eso fue divertido ...
user435779
Habiendo comenzado en pedazos, pensé que ESO era endianess durante mucho tiempo.
Roy Falk
20

No hay enteros sin firmar en Java. Todos los números enteros están firmados y en big endian.

En el lado C, cada byte tiene el LSB al principio a la izquierda y el MSB al final.

Parece que estás usando LSB como el bit menos significativo, ¿verdad? LSB generalmente significa byte menos significativo. Endianness no se basa en bits sino en bytes.

Para convertir de un byte sin firmar a un entero de Java:

int i = (int) b & 0xFF;

Para convertir de little-endian de 32 bits sin firmar en byte [] a Java long (desde la parte superior de mi cabeza, no probado):

long l = (long)b[0] & 0xFF;
l += ((long)b[1] & 0xFF) << 8;
l += ((long)b[2] & 0xFF) << 16;
l += ((long)b[3] & 0xFF) << 24;
Jonas Elfström
fuente
me acabo de dar cuenta de eso: $ entonces, ¿cómo se supone que debo enviar este pequeño endian sin firmar a mi proceso de Java para leerlo correctamente?
hhafez
lo que quiero decir con el comienzo es que lsb está al comienzo de los 4 bytes (es un int de 32 bits sin firmar), así que quise decir el byte menos significativo
hhafez
También estoy convirtiendo de C -> Java no de Java -> C :)
hhafez
Su código funciona bien, siempre que elimine el punto y coma después de 0xFF en las últimas tres líneas. Lo editaría yo mismo, pero eso es un cambio de menos de 6 caracteres.
Moose Morals
1
Tomó casi 8 años, pero finalmente alguien detectó el error de sintaxis. Gracias @MooseMorals :)
Jonas Elfström
12

No hay forma de que esto pueda influir en nada en Java, ya que no hay una forma (directa sin API) de mapear algunos bytes directamente en un int en Java.

Cada API que hace esto o algo similar define el comportamiento con bastante precisión, por lo que debe buscar la documentación de esa API.

Joachim Sauer
fuente
3
Oh, seguro que lo hay. Las matemáticas binarias (&, |, <<, etc.) funcionan bien en bytes e ints. Es bastante fácil tomar bytes arbitrarios y pegarlos en un número entero.
Herms
8
Pero si hace esto, todavía no puede saber qué endianess utiliza internamente su JVM.
Darron
4
Sí, pero incluso allí no estás mapeando directamente. Está utilizando aritmética que hace exactamente lo que le dice, no hay ambigüedad. En C, siempre se puede convertir un "byte *" en un "largo *" y eliminar la referencia. Entonces tendrías que preocuparte por la endiacidad. En Java no hay una forma directa y ambigua de hacerlo.
Joachim Sauer
Ah, ya veo. Estabas hablando del elenco, no de las matemáticas binarias. Sí, en ese caso tienes razón.
Herms
10
+1 para "buscar la documentación", pero NOTA: la primera oración ya no es correcta ya que hoy en día el paquete NIO ofrece ByteBuffer que puede asignar bytes a primitivas y donde puede cambiar el orden de bytes. Ver ByteBuffer y ByteOrder
user85421
3

Leería los bytes uno por uno y los combinaría en un valor largo . De esa forma controlas la endianidad y el proceso de comunicación es transparente.

Wouter Lievens
fuente
¿Te importaría comentar por qué me estás rechazando?
Wouter Lievens
porque incluso si tuviera que leer cada byte individualmente, la endiabilidad del byte que se envía sería incorrecta, por lo que tendría que convertirlo
hhafez
23
¿Endianidad de un byte? ¿Qué demonios es eso? Las palabras son sensibles a la endianidad, los bytes individuales no.
Wouter Lievens
3
@hhafez Eso no es cierto, los bytes no tienen endianess en lo que a nosotros respecta. Si lee byte a byte, usted, el programador, es responsable de asignar los bytes al lugar adecuado. Eso es exactamente lo que hace DataInputStream, simplemente ensambla los bytes juntos de una manera Big Endian bajo las capotas.
nos
2
@WouterLievens: Me he encontrado con algunos dispositivos de E / S (por ejemplo, un chip de reloj en tiempo real) que, por cualquier motivo, envían datos en formato de bit invertido; después de recibir datos de ellos, es necesario invertir los bits en cada byte. Sin embargo, estoy de acuerdo con usted en que la endianidad de los bytes no suele ser un problema, a menos que uno tenga que lidiar con piezas de hardware particulares de diseño extraño.
supergato
3

Si se ajusta al protocolo que usa, considere usar un DataInputStream, donde el comportamiento está muy bien definido .

Ilja Preuß
fuente
1
Solo puede hacer eso si su protocolo usa el mismo endianness.
Wouter Lievens
Arreglé el enlace y lo cambié para que apunte a Java 9, la versión actual. Sin embargo, la API en cuestión se introdujo en Java 1.0.
Jens Bannmann
2

Java es 'Big-endian' como se señaló anteriormente. Eso significa que el MSB de un int está a la izquierda si examina la memoria (en una CPU Intel al menos). El bit de signo también está en el MSB para todos los tipos de enteros de Java.
Leer un entero sin signo de 4 bytes de un archivo binario almacenado por un sistema 'Little-endian' requiere un poco de adaptación en Java. ReadInt () de DataInputStream espera el formato Big-endian.
Aquí hay un ejemplo que lee un valor sin signo de cuatro bytes (como lo muestra HexEdit como 01 00 00 00) en un número entero con un valor de 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;        
 }
Donald W. Smith
fuente
¿A qué se refiere "anotado arriba"? El orden en el que se muestran las respuestas SO puede variar.
LarsH
0

java force de hecho big endian: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.11

usuario12482548
fuente
3
Se trata de la endianidad de las instrucciones del código de bytes, no de la endianidad de los datos en tiempo de ejecución.
kaya3
Estoy votando. Este fragmento byte[] bbb = ByteBuffer.allocate(4).putFloat(0.42f).array();produjo unbyte matriz que es la inversa de lo que C/C++produjo mi . Por lo tanto, el gran endianness de Java tiene efecto incluso en los datos en tiempo de ejecución.
truthadjustr