Czy Java odczytuje liczby całkowite w little endian lub big endian?

96

Pytam, ponieważ wysyłam strumień bajtów z procesu C do Javy. Po stronie C 32-bitowa liczba całkowita ma LSB to pierwszy bajt, a MSB to czwarty bajt.

Moje pytanie brzmi: po stronie Javy, kiedy odczytujemy bajt wysłany z procesu C, czym jest endian po stronie Javy?

Pytanie uzupełniające: Jeśli endian po stronie Java nie jest tym samym, co wysłany, jak mogę dokonać konwersji między nimi?

hhafez
źródło
2
Oto moja mnemonika do tego, więc nie zapomnę: Java to nie sprzęt, ale wirtualna, jest językiem internetu. Sieciowej kolejności bajtów jest big endian . Dlatego Java to big endian .
eigenfield

Odpowiedzi:

67

Użyj sieciowej kolejności bajtów (big endian), która i tak jest taka sama, jakiej używa Java. Zobacz man htons dla różnych tłumaczy w C.

Egil
źródło
Nie jestem teraz przy moim Linuksie, ale czy Htons jest jedną ze standardowych bibliotek?
hhafez
Według h30097.www3.hp.com/docs//base_doc/DOCUMENTATION/V51_HTML/MAN/ ... jego część standardowej biblioteki c, tak
Egil
1
htons jest dostępny prawie wszędzie, ale nie ma go w ISO C.
MSalters
1
Jeśli musisz użyć czegoś innego niż kolejność bajtów w sieci, możesz albo utworzyć własne z operatorami bitowymi, albo użyć różnych wersji java.nio.Buffer
Darron
1
Zgodnie z jego stroną podręcznika jest zdefiniowana w POSIX.1, więc powinna być dostępna prawie wszędzie. Wydaje mi się, że pamiętam, że używałem go w Win32, więc nie tylko w systemach POSIX.
Joachim Sauer
50

Natknąłem się tutaj przez Google i otrzymałem odpowiedź, że Java to big endian .

Czytając odpowiedzi, chciałbym zwrócić uwagę, że bajty rzeczywiście mają kolejność endian, chociaż na szczęście, jeśli miałeś do czynienia tylko z mikroprocesorami „głównego nurtu”, prawdopodobnie nie spotkałeś ich nigdy jako Intel, Motorola i Zilog zgodzili się co do kierunku przesunięcia ich układów UART i że MSB bajtu będzie, 2**7a LSB będzie 2**0w ich procesorach (użyłem notacji mocy FORTRAN, aby podkreślić, ile lat ma ten materiał :)).

Napotkałem ten problem z niektórymi szeregowymi danymi łącza w dół Space Shuttle 20+ lat temu, kiedy wymieniliśmy sprzęt interfejsu za 10 000 USD na komputer Mac. Już dawno temu opublikowano krótki opis techniczny NASA. Po prostu użyłem 256-elementowej tabeli wyszukiwania z odwróconymi bitami ( table[0x01]=0x80itp.) Po przesunięciu każdego bajtu ze strumienia bitów.

WB Greene
źródło
Świetny wgląd! Mam to pytanie i nie mam odpowiedzi w sieci.
Xolve
jeśli któryś z nich byłby publiczny, czy mógłbyś połączyć krótkie informacje techniczne NASA (i zgadnąć, że prom kosmiczny bituje dane szeregowego łącza w dół), o którym mówisz? byłoby fascynujące, nigdy nie widziałem czegoś takiego.
n611x007
3
Bitwise endianness pojawia się również w przypadku formatów kompresji, które używają jakiejś formy kodowania Huffmana (tj. Wszystkich z nich). Dla dodatkowej zabawy, JPEG to „bitowy big-endian” (tj. Najbardziej znaczący bit to „pierwszy” bit), a LZ to „bitowy little-endian”. Kiedyś pracowałem nad zastrzeżonym formatem kompresji, który używał obu formatów pod maską. Och, to było fajne ...
user435779
Zaczynając od kawałków, przez długi czas myślałem, że to koniec.
Roy Falk
20

W Javie nie ma liczb całkowitych bez znaku. Wszystkie liczby całkowite są podpisane i zapisane w big endian.

Po stronie C każdy bajt ma na początku LSB, a na końcu MSB.

Wygląda na to, że używasz LSB jako najmniej znaczącego kawałka, prawda? LSB zwykle oznacza najmniej znaczący bajt. Endianness nie jest oparty na bitach, ale na bajtach.

Aby przekonwertować bajt bez znaku na liczbę całkowitą Java:

int i = (int) b & 0xFF;

Aby przekonwertować z 32-bitowego little-endian bez znaku w bajcie [] do języka Java (od początku mojej głowy, nie testowane):

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
źródło
właśnie sobie sprawę, że: $ więc jak mam wysłać ten niepodpisany mały endian do mojego procesu java, aby go poprawnie odczytać?
hhafez
co mam na myśli na początku, to że lsb znajduje się na początku 4 bajtów (jest to 32-bitowy int bez znaku), więc miałem na myśli najmniej znaczący bajt
hhafez
Konwertuję również z C -> Java nie z Java -> C :)
hhafez
Twój kod działa dobrze, o ile usuniesz średnik po 0xFF w ostatnich trzech wierszach. Sam bym go edytował, ale to zmiana o mniej niż 6 znaków.
Moose Morals
1
Zajęło to prawie 8 lat, ale w końcu ktoś zauważył błąd składniowy. Dzięki @MooseMorals :)
Jonas Elfström
12

Nie ma sposobu, aby mogło to wpłynąć na cokolwiek w Javie, ponieważ nie ma (bezpośredniego, innego niż API) sposobu mapowania niektórych bajtów bezpośrednio na int w Javie.

Każde API, które robi to lub coś podobnego, dość precyzyjnie definiuje zachowanie, więc powinieneś zajrzeć do dokumentacji tego API.

Joachim Sauer
źródło
3
Jasne, że jest. Matematyka binarna (&, |, <<, itp.) Działa dobrze na bajtach i intach. Dość łatwo jest wziąć dowolne bajty i umieścić je w liczbie całkowitej.
Herms
8
Ale jeśli to zrobisz, nadal nie możesz określić, jakich endianess używa Twoja JVM wewnętrznie.
Darron
4
Tak, ale nawet tam nie mapujesz bezpośrednio. Używasz arytmetyki, która robi dokładnie to, co jej powiesz, nie ma dwuznaczności. W C zawsze można było rzutować „bajt *” na „długi *” i usuwać z niego odniesienia. Wtedy musiałbyś dbać o endianessę. W Javie nie ma na to bezpośredniego, dwuznacznego sposobu.
Joachim Sauer,
O, rozumiem. Mówiłeś o obsadzie, a nie o matematyce binarnej. Tak, w takim razie masz rację.
Herms
10
+1 za "przeszukaj dokumentację", ale UWAGA: pierwsze zdanie nie jest już poprawne, ponieważ obecnie pakiet NIO oferuje ByteBuffer, który może mapować bajty na prymitywy i gdzie można zmienić kolejność bajtów. Zobacz ByteBuffer i ByteOrder
user85421
3

Czytałem bajty jeden po drugim i łączyłem je w długą wartość. W ten sposób kontrolujesz endianness, a proces komunikacji jest przejrzysty.

Wouter Lievens
źródło
Chcesz skomentować, dlaczego głosujesz na mnie przeciw?
Wouter Lievens,
ponieważ nawet gdybym czytał każdy bajt indywidualnie, endianess wysyłanego bajtu byłby niepoprawny, więc musiałbym go przekonwertować
hhafez
23
Endianness bajtu? Co to do diabła jest? Słowa są wrażliwe na endianness, a pojedyncze bajty nie.
Wouter Lievens,
3
@hhafez To nie jest prawda, bajty nie mają endianess, o ile musimy się o to martwić, jeśli czytasz bajt po bajcie, ty, programista, jesteś odpowiedzialny za przypisanie bajtów we właściwe miejsce. To jest dokładnie to, co robi DataInputStream, po prostu łączy bajty razem w big endian pod maskami.
nr
2
@WouterLievens: Napotkałem kilka urządzeń I / O (np. Chip zegara czasu rzeczywistego), które z jakiegokolwiek powodu wysyłają dane w formacie odwróconym bitowo; po otrzymaniu od nich danych konieczne jest odwrócenie bitów w każdym bajcie. Zgadzam się jednak z tym, że endian -ness bajtów nie jest generalnie problemem, chyba że trzeba mieć do czynienia z konkretnymi, dziwnie zaprojektowanymi elementami sprzętu.
supercat
3

Jeśli pasuje do używanego protokołu, rozważ użycie DataInputStream, gdzie zachowanie jest bardzo dobrze zdefiniowane .

Ilja Preuß
źródło
1
Może to zrobić tylko wtedy, gdy jego protokół używa tej samej endianness.
Wouter Lievens,
Naprawiłem łącze i zmieniłem je tak, aby wskazywało na Javę 9, bieżącą wersję. Jednak omawiany interfejs API został wprowadzony w Javie 1.0.
Jens Bannmann
2

Jak wspomniano powyżej, Java to „Big-endian”. Oznacza to, że MSB int znajduje się po lewej stronie, jeśli zbadasz pamięć (przynajmniej na procesorze Intela). Bit znaku znajduje się również w MSB dla wszystkich typów całkowitych Java.
Odczyt 4-bajtowej liczby całkowitej bez znaku z pliku binarnego przechowywanego w systemie „Little-endian” wymaga pewnych adaptacji w Javie. Funkcja readInt () DataInputStream oczekuje formatu Big-endian.
Oto przykład, który odczytuje czterobajtową wartość bez znaku (wyświetlaną przez HexEdit jako 01 00 00 00) na liczbę całkowitą o wartości 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
źródło
Do czego odnosi się „zaznaczone powyżej”? Kolejność, w jakiej wyświetlane są odpowiedzi SO, może się różnić.
LarsH
0

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

user12482548
źródło
3
Chodzi o endianness instrukcji kodu bajtowego, a nie endianness danych w czasie wykonywania.
kaya3
Głosuję za. Ten fragment byte[] bbb = ByteBuffer.allocate(4).putFloat(0.42f).array();produkowane bytetablicę, która jest odwrotnością tego, co mój C/C++produkowane. W związku z tym duże możliwości języka Java mają wpływ nawet na dane w czasie wykonywania.
eigenfield