Apakah Java membaca bilangan bulat di little endian atau big endian?

94

Saya bertanya karena saya mengirim aliran byte dari proses C ke Java. Di sisi C, integer 32 bit memiliki LSB adalah byte pertama dan MSB adalah byte ke-4.

Jadi pertanyaan saya adalah: Di sisi Java ketika kita membaca byte seperti yang dikirim dari proses C, apa itu endian di sisi Java?

Pertanyaan lanjutan: Jika endian di sisi Java tidak sama dengan yang dikirim, bagaimana cara mengonversi di antara keduanya?

hhafez.dll
sumber
1
Ini adalah mnemonik saya untuk ini jadi saya tidak akan lupa: Java bukanlah perangkat keras melainkan virtual, adalah bahasa internet. Urutan byte jaringan adalah big endian . Oleh karena itu, Java adalah big endian .
eigenfield

Jawaban:

66

Gunakan urutan byte jaringan (big endian), yang sama dengan yang digunakan Java. Lihat man htons untuk berbagai penerjemah dalam C.

Agil
sumber
Saya tidak berada di kotak linux saya sekarang tetapi apakah htons salah satu lib standar?
hhafez
Menurut h30097.www3.hp.com/docs//base_doc/DOCUMENTATION/V51_HTML/MAN/… bagiannya dari pustaka c standar, ya
Agil
1
htons tersedia hampir di semua tempat, tetapi tidak dalam ISO C.
MSalters
1
Jika Anda harus menggunakan sesuatu selain urutan byte jaringan, maka Anda dapat menggulung sendiri dengan operator bitwise atau menggunakan berbagai versi java.nio.Buffer
Darron
1
Menurut halaman manualnya, ini didefinisikan di POSIX.1, jadi itu harus tersedia di mana-mana. Dan sepertinya saya ingat pernah menggunakannya di Win32, jadi ini juga bukan hanya di sistem POSIX.
Joachim Sauer
48

Saya tersandung di sini melalui Google dan mendapat jawaban saya bahwa Java adalah big endian .

Membaca tanggapan saya ingin menunjukkan bahwa byte memang memiliki urutan endian, meskipun untungnya, jika Anda hanya berurusan dengan mikroprosesor "arus utama" Anda tidak mungkin pernah menemukannya seperti Intel, Motorola, dan Zilog semua menyetujui arah pergeseran chip UART mereka dan bahwa MSB byte akan 2**7dan LSB akan berada 2**0di CPU mereka (saya menggunakan notasi daya FORTRAN untuk menekankan berapa umur barang ini :)).

Saya mengalami masalah ini dengan beberapa data downlink serial bit Space Shuttle 20+ tahun yang lalu ketika kami mengganti perangkat keras antarmuka $ 10K dengan komputer Mac. Ada laporan singkat NASA Tech yang diterbitkan tentang itu sejak lama. Saya hanya menggunakan tabel pencarian elemen 256 dengan bit dibalik ( table[0x01]=0x80dll.) Setelah setiap byte digeser dari aliran bit.

WB Greene
sumber
Wawasan luar biasa! Saya memiliki pertanyaan ini dan tidak ada jawaban di web.
Xolve
Jika ada yang bersifat publik, dapatkah Anda menautkan ringkasan teknis NASA (dan mungkin data downlink serial bit pesawat luar angkasa) yang Anda bicarakan? akan menarik, saya belum pernah melihat yang seperti itu.
n611x007
3
Bitwise endianness juga ikut bermain dengan format kompresi yang menggunakan beberapa bentuk pengkodean Huffman (yaitu semuanya). Untuk kesenangan ekstra, JPEG adalah "bitwise big-endian" (yaitu bit yang paling signifikan adalah bit "pertama") dan LZ adalah "bitwise little-endian". Saya pernah mengerjakan format kompresi berpemilik yang menggunakan kedua format di bawah tenda. Oh, itu menyenangkan ...
user435779
Setelah memulai sedikit-sedikit, saya pikir ITULAH endianess untuk waktu yang lama.
Roy Falk
20

Tidak ada bilangan bulat yang tidak bertanda tangan di Java. Semua bilangan bulat ditandatangani dan di big endian.

Di sisi C, setiap byte memiliki LSB di awal di sebelah kiri dan MSB di akhir.

Sepertinya Anda menggunakan LSB sebagai Sedikit signifikan, bukan? LSB biasanya singkatan dari byte paling signifikan. Endianness tidak berbasis bit tetapi berbasis byte.

Untuk mengonversi dari byte unsigned menjadi integer Java:

int i = (int) b & 0xFF;

Untuk mengonversi dari 32-bit little-endian unsigned dalam byte [] ke Java long (dari atas kepala saya, tidak diuji):

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
sumber
baru menyadari bahwa: $ jadi bagaimana saya bisa mengirim little endian unsigned ini ke proses java saya untuk membacanya dengan benar?
hhafez
yang saya maksud pada awalnya adalah bahwa lsb berada di awal 4 byte (ini adalah int 32 bit unsigned) jadi yang saya maksud adalah byte paling signifikan
hhafez
Juga saya mengonversi dari C -> Java bukan dari Java -> C :)
hhafez
Kode Anda berfungsi dengan baik, selama Anda menghapus titik koma setelah 0xFF di tiga baris terakhir. Saya akan mengeditnya sendiri, tapi itu perubahan kurang dari 6 karakter.
Moose Morals
1
Butuh waktu hampir 8 tahun tetapi akhirnya seseorang melihat kesalahan sintaks. Terima kasih @MooseMorals :)
Jonas Elfström
12

Tidak mungkin hal ini dapat memengaruhi apa pun di Java, karena tidak ada cara (non-API langsung) untuk memetakan beberapa byte secara langsung ke int di Java.

Setiap API yang melakukan ini atau sesuatu yang serupa mendefinisikan perilakunya dengan cukup tepat, jadi Anda harus mencari dokumentasi API tersebut.

Joachim Sauer
sumber
3
Oh tentu ada. Matematika biner (&, |, <<, dll) berfungsi dengan baik pada byte dan int. Sangat mudah untuk mengambil byte yang berubah-ubah dan memasukkannya ke dalam bilangan bulat.
Herms
8
Tetapi jika Anda melakukan ini, Anda masih tidak tahu apa endianess yang digunakan JVM Anda secara internal.
Darron
4
Ya, tetapi bahkan di sana Anda tidak secara langsung memetakan. Anda menggunakan aritmatika yang melakukan apa yang Anda katakan, tidak ada ambiguitas. Di C Anda selalu bisa mentransmisikan "byte *" ke "long *" dan membatalkan referensi itu. Maka Anda harus peduli dengan kesabaran. Di Jawa tidak ada cara yang langsung dan ambigu untuk melakukan itu.
Joachim Sauer
Ah, begitu. Anda berbicara tentang pemerannya, bukan matematika biner. Ya, kalau begitu Anda benar.
Herms
10
+1 untuk "lihat dokumentasi", tetapi CATATAN: kalimat pertama tidak benar lagi karena saat ini paket NIO menawarkan ByteBuffer yang dapat memetakan byte ke primitif dan di mana Anda dapat mengubah urutan byte. Lihat ByteBuffer dan ByteOrder
pengguna85421
3

Saya akan membaca byte satu per satu, dan menggabungkannya menjadi nilai yang panjang . Dengan cara itu Anda mengontrol endianness, dan proses komunikasinya transparan.

Wouter Lievens
sumber
Mau berkomentar mengapa Anda memilih saya?
Wouter Lievens
karena bahkan jika saya membaca setiap byte secara individual, endianess byte yang dikirim akan salah jadi saya perlu mengubahnya
hhafez
23
Endianness dari satu byte? Apa-apaan itu? Kata-kata sensitif terhadap ketangguhan, sedangkan byte individu tidak.
Wouter Lieven
3
@hhafez Itu tidak benar, byte tidak memiliki endianess sejauh yang perlu kita perhatikan jika Anda membaca byte demi byte, Anda, programmer bertanggung jawab untuk menetapkan byte ke tempat yang tepat. Itulah yang dilakukan DataInputStream, itu hanya mengumpulkan byte bersama-sama dengan cara yang besar di bawah tenda.
no
2
@WouterLievens: Saya menemukan beberapa perangkat I / O (misalnya chip jam waktu nyata) yang, untuk alasan apa pun, mengirimkan data dalam format bit-terbalik; setelah menerima data dari mereka, bit-bit di setiap byte perlu dibalik. Saya setuju dengan Anda, bagaimanapun, bahwa endian-an-ness byte umumnya tidak menjadi masalah, kecuali seseorang harus berurusan dengan perangkat keras tertentu yang dirancang aneh.
supercat
3

Jika sesuai dengan protokol yang Anda gunakan, pertimbangkan untuk menggunakan DataInputStream, di mana perilakunya didefinisikan dengan sangat baik .

Ilja Preuß
sumber
1
Dia hanya dapat melakukan itu jika protokolnya menggunakan endianness yang sama.
Wouter Lievens
Saya memperbaiki tautannya, dan mengubahnya agar mengarah ke Java 9, rilis saat ini. API yang dimaksud diperkenalkan di Java 1.0.
Jens Bannmann
2

Java adalah 'Big-endian' seperti disebutkan di atas. Itu berarti bahwa MSB dari sebuah int ada di sebelah kiri jika Anda memeriksa memori (setidaknya pada CPU Intel). Bit tanda juga ada di MSB untuk semua tipe integer Java.
Membaca 4 byte unsigned integer dari file biner yang disimpan oleh sistem 'Little-endian' membutuhkan sedikit adaptasi di Java. ReadInt () DataInputStream mengharapkan format Big-endian.
Berikut adalah contoh yang membaca nilai unsigned empat byte (seperti yang ditampilkan oleh HexEdit sebagai 01 00 00 00) menjadi bilangan bulat dengan nilai 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
sumber
Apa yang dimaksud dengan "disebutkan di atas"? Urutan di mana jawaban SO ditampilkan dapat bervariasi.
LarsH
0

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

pengguna12482548
sumber
3
Ini tentang endianness dari instruksi bytecode, bukan endianness data pada waktu proses.
kaya3
Saya sedang voting. Potongan ini byte[] bbb = ByteBuffer.allocate(4).putFloat(0.42f).array();menghasilkan bytearray yang merupakan kebalikan dari apa yang saya C/C++hasilkan. Oleh karena itu, pengaruh besar Java berlaku bahkan dalam data pada waktu proses.
eigenfield