Java legge interi in little endian o big endian?


94

Chiedo perché sto inviando un flusso di byte da un processo C a Java. Sul lato C il numero intero a 32 bit ha LSB come primo byte e MSB è il quarto byte.

Quindi la mia domanda è: sul lato Java, quando leggiamo il byte come è stato inviato dal processo C, cos'è endian sul lato Java?

Una domanda di follow-up: se l'endian sul lato Java non è lo stesso di quello inviato, come posso convertirli tra loro?


1
Ecco i miei mnemonici per questo, quindi non dimenticherò: Java non è hardware ma invece virtuale, è il linguaggio di Internet. L' ordine dei byte di rete è big endian . Pertanto, Java è big endian .
truthadjustr

Risposte:


66

Usa l'ordine dei byte di rete (big endian), che è lo stesso che Java usa comunque. Vedi man htons per i diversi traduttori in C.


Non sono al mio box Linux adesso, ma htons è una delle librerie standard?
hhafez

Secondo h30097.www3.hp.com/docs//base_doc/DOCUMENTATION/V51_HTML/MAN/… fa parte della libreria standard c, sì
Egil

1
htons è disponibile quasi ovunque, ma non è in ISO C.
MSalters

1
Se devi usare qualcosa di diverso dall'ordine dei byte di rete, puoi eseguire il rollio del tuo con operatori bit per bit o utilizzare le varie versioni di java.nio
Darron

1
Secondo la sua pagina di manuale è definito in POSIX.1, quindi dovrebbe essere disponibile praticamente ovunque. E mi sembra di ricordare di usarlo in Win32, quindi non è nemmeno solo sui sistemi POSIX.
Joachim Sauer

47

Sono inciampato qui tramite Google e ho ottenuto la mia risposta che Java è big endian .

Leggendo le risposte vorrei sottolineare che i byte hanno effettivamente un ordine endian, anche se per fortuna, se hai avuto a che fare solo con microprocessori "tradizionali", è improbabile che tu lo abbia mai incontrato come Intel, Motorola e Zilog tutti concordato sulla direzione di spostamento dei loro chip UART e che MSB di un byte sarebbe stato 2**7e LSB sarebbe stato 2**0nelle loro CPU (ho usato la notazione di potenza FORTRAN per enfatizzare quanti anni ha questa roba :)).

Mi sono imbattuto in questo problema con alcuni dati di downlink seriali dello Space Shuttle più di 20 anni fa, quando abbiamo sostituito un hardware di interfaccia da $ 10.000 con un computer Mac. C'è un brief della NASA Tech pubblicato su di esso molto tempo fa. Ho semplicemente usato una tabella di ricerca a 256 elementi con i bit invertiti ( table[0x01]=0x80ecc.) Dopo che ogni byte è stato spostato dal flusso di bit.


Ottima intuizione! Ho questa domanda e nessuna risposta nel web.
Xolve

se qualcuno di loro è pubblico, potresti collegare il brief tecnico della NASA (e forse i dati di downlink seriali del bit dello space shuttle) di cui parli? sarebbe affascinante, non ho mai visto una cosa del genere.
n611x007

3
L'endianità bit per bit entra in gioco anche con i formati di compressione che utilizzano una qualche forma di codifica Huffman (cioè tutti). Per un divertimento extra, JPEG è "bitwise big-endian" (cioè il bit più significativo è il "primo" bit) e LZ è "bitwise little-endian". Una volta ho lavorato su un formato di compressione proprietario che utilizzava entrambi i formati sotto il cofano. Oh, è stato divertente ...
user435779

Avendo iniziato a bit, ho pensato che QUELLA fosse endianess per molto tempo.
Roy Falk

20

Non ci sono numeri interi senza segno in Java. Tutti i numeri interi sono firmati e in big endian.

Sul lato C ogni byte ha l'LSB all'inizio è a sinistra e l'MSB alla fine.

Sembra che tu stia usando LSB come bit meno significativo, vero? LSB di solito sta per byte meno significativo. Endianness non è basato su bit ma su byte.

Per convertire da un byte senza segno a un intero Java:

int i = (int) b & 0xFF;

Per convertire da little endian a 32 bit senza segno in byte [] a Java long (dalla parte superiore della mia testa, non testato):

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

appena realizzato che: $ quindi come dovrei inviare questo little endian non firmato al mio processo java per leggerlo correttamente?
hhafez

whay intendo con l'inizio è che lsb è all'inizio dei 4 byte (è un int a 32 bit senza segno) quindi intendevo byte meno significativo
hhafez

Inoltre sto convertendo da C -> Java non da Java -> C :)
hhafez

Il tuo codice funziona bene, a condizione che rimuovi il punto e virgola dopo 0xFF nelle ultime tre righe. Lo modificherei da solo, ma è un cambiamento di meno di 6 caratteri.
Moose Morals

1
Ci sono voluti quasi 8 anni ma alla fine qualcuno ha individuato l'errore di sintassi. Grazie @MooseMorals :)
Jonas Elfström

12

Non c'è modo che questo possa influenzare qualcosa in Java, poiché non esiste un modo (diretto non API) per mappare alcuni byte direttamente in un int in Java.

Ogni API che fa questo o qualcosa di simile definisce il comportamento in modo abbastanza preciso, quindi dovresti cercare la documentazione di quell'API.


3
Oh certo che c'è. La matematica binaria (&, |, <<, ecc.) Funziona perfettamente su byte e int. È abbastanza facile prendere byte arbitrari e inserirli in un numero intero.
Herms

8
Ma se lo fai, non puoi ancora dire quale endianess utilizza internamente la tua JVM.
Darron

4
Sì, ma anche lì non stai mappando direttamente. Stai usando l'aritmetica che fa esattamente quello che dici, non c'è ambiguità. In C puoi sempre lanciare un "byte *" a un "lungo *" e de-referenziarlo. Allora dovresti preoccuparti dell'endianess. In Java non esiste un modo diretto e ambiguo per farlo.
Joachim Sauer

Ah, capisco. Stavi parlando del cast, non della matematica binaria. Sì, in quel caso hai ragione.
Herms

10
+1 per la "ricerca della documentazione", ma NOTA: la prima frase non è più corretta poiché al giorno d'oggi il pacchetto NIO offre ByteBuffer che può mappare byte a primitive e dove è possibile cambiare l'ordine dei byte. Vedi ByteBuffer e ByteOrder
user85421

3

Leggevo i byte uno per uno e li combinavo in un valore lungo . In questo modo controlli l'endianness e il processo di comunicazione è trasparente.


Ti va di commentare perché mi stai votando?
Wouter Lievens

perché anche se dovessi leggere ogni byte individualmente, l'endianess del byte che viene inviato non sarebbe corretto quindi avrei bisogno di convertirlo
hhafez

23
Endianness di un byte? Che diavolo è quello? Le parole sono sensibili all'endianità, i singoli byte no.
Wouter Lievens

3
@hhafez Questo non è vero, i byte non hanno endianess per quanto dobbiamo preoccuparci se leggi byte per byte, tu, il programmatore, sei responsabile dell'assegnazione dei byte al posto giusto. Questo è esattamente ciò che fa DataInputStream, assembla semplicemente i byte insieme in un modo big endian sotto i cofani.
n.

2
@WouterLievens: ho riscontrato alcuni dispositivi I / O (ad esempio un chip di clock in tempo reale) che, per qualsiasi motivo, inviano dati in formato bit-invertito; dopo aver ricevuto i dati da loro, è necessario invertire i bit in ogni byte. Sono d'accordo con te, tuttavia, sul fatto che l'endianità dei byte non è generalmente un problema, a meno che non si abbia a che fare con particolari componenti hardware progettati in modo strano.
supercat

3

Se si adatta al protocollo che utilizzi, considera l'utilizzo di un DataInputStream, dove il comportamento è molto ben definito .


1
Può farlo solo se il suo protocollo utilizza lo stesso endianness.
Wouter Lievens

Ho corretto il collegamento e l'ho modificato in modo che punti a Java 9, la versione corrente. Tuttavia, l'API in questione è stata introdotta in Java 1.0.
Jens Bannmann

2

Java è "Big-endian" come indicato sopra. Ciò significa che l'MSB di un int è a sinistra se si esamina la memoria (almeno su una CPU Intel). Il bit di segno si trova anche nell'MSB per tutti i tipi interi Java.
La lettura di un intero senza segno a 4 byte da un file binario memorizzato da un sistema 'Little-endian' richiede un po 'di adattamento in Java. ReadInt () di DataInputStream prevede il formato Big-endian.
Ecco un esempio che legge un valore senza segno di quattro byte (come visualizzato da HexEdit come 01 00 00 00) in un numero intero con un valore di 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;        
 }

A cosa si riferisce "annotato sopra"? L'ordine in cui vengono visualizzate le risposte SO può variare.
LarsH

0

3
Si tratta di endianness delle istruzioni bytecode, non endianness dei dati in fase di esecuzione.
kaya3

Sto votando. Questo frammento ha byte[] bbb = ByteBuffer.allocate(4).putFloat(0.42f).array();prodotto un bytearray che è il contrario di quello che ho C/C++prodotto. Pertanto, la grande endianness di Java ha effetto anche nei dati in fase di runtime.
truthadjustr
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.