Java อ่านจำนวนเต็มใน endian น้อยหรือ big endian หรือไม่?


96

ฉันถามเพราะฉันกำลังส่งสตรีมไบต์จากกระบวนการ C ไปยัง Java ทางด้าน C จำนวนเต็ม 32 บิตมี LSB เป็นไบต์แรกและ MSB คือไบต์ที่ 4

คำถามของฉันคือ: ในฝั่ง Java เมื่อเราอ่านไบต์ตามที่ส่งมาจากกระบวนการ C endianในฝั่ง Java คืออะไร?

คำถามติดตามผล: หาก endian ในฝั่ง Java ไม่เหมือนกับที่ส่งมาฉันจะแปลงระหว่างพวกเขาได้อย่างไร


2
นี่คือสิ่งช่วยจำของฉันสำหรับสิ่งนี้ดังนั้นฉันจะไม่ลืม: Java ไม่ใช่ฮาร์ดแวร์ แต่เป็นเสมือนจริงเป็นภาษาของอินเทอร์เน็ต เครือข่ายเพื่อ byteเป็นendian ใหญ่ ดังนั้น Java เป็นendian ใหญ่
eigenfield

คำตอบ:


67

ใช้คำสั่งไบต์เครือข่าย (endian ใหญ่) ซึ่งเหมือนกับที่ Java ใช้อยู่ดี ดู man htons สำหรับนักแปลที่แตกต่างกันใน C.


ตอนนี้ฉันไม่ได้อยู่ที่กล่อง linux แต่ htons เป็นหนึ่งใน libs มาตรฐานหรือไม่
hhafez

อ้างอิงจากh30097.www3.hp.com/docs//base_doc/DOCUMENTATION/V51_HTML/MAN/…เป็นส่วนหนึ่งของไลบรารี c มาตรฐานใช่
Egil

1
htons มีให้บริการเกือบทุกที่ แต่ไม่มีใน ISO C
MSalters

1
หากคุณต้องใช้สิ่งอื่นนอกเหนือจากคำสั่งไบต์เครือข่ายคุณอาจหมุนตัวเองด้วยตัวดำเนินการแบบบิตหรือใช้ java.nio.Buffer เวอร์ชันต่างๆ
Darron

1
ตามหน้าของมันถูกกำหนดไว้ใน POSIX.1 ดังนั้นจึงควรมีอยู่ทุกที่ และฉันดูเหมือนจะจำได้ว่าใช้ใน Win32 ดังนั้นจึงไม่ใช่แค่ในระบบ POSIX เท่านั้น
Joachim Sauer

51

ฉันสะดุดที่นี่ผ่าน Google และได้รับคำตอบว่า Java นั้นใหญ่มาก

การอ่านคำตอบฉันต้องการชี้ให้เห็นว่าไบต์มีคำสั่ง endian แม้ว่าจะเป็นไปอย่างมีเมตตาหากคุณจัดการกับไมโครโปรเซสเซอร์ "กระแสหลัก" เท่านั้นคุณไม่น่าจะเคยพบมาก่อนเช่น Intel, Motorola และ Zilog ทั้งหมด ตกลงกันเกี่ยวกับทิศทางการเปลี่ยนแปลงของชิป UART ของพวกเขาและ MSB ของไบต์จะเป็น 2**7และ LSB จะอยู่2**0ในซีพียูของพวกเขา (ฉันใช้สัญกรณ์พลังงาน FORTRAN เพื่อเน้นว่าสิ่งนี้เก่าแค่ไหน :))

ฉันพบปัญหานี้กับข้อมูลดาวน์ลิงค์อนุกรมของ Space Shuttle bit เมื่อ 20+ ปีก่อนเมื่อเราเปลี่ยนฮาร์ดแวร์อินเทอร์เฟซมูลค่า 10,000 เหรียญด้วยคอมพิวเตอร์ Mac มีข้อมูลสรุปของ NASA Tech ที่เผยแพร่เมื่อนานมาแล้ว ฉันใช้ตารางค้นหาองค์ประกอบ 256 รายการโดยมีการย้อนกลับของบิต ( table[0x01]=0x80ฯลฯ ) หลังจากที่แต่ละไบต์ถูกเลื่อนเข้ามาจากสตรีมบิต


เจาะลึกสุด ๆ ! ฉันมีคำถามนี้และไม่มีคำตอบในเว็บ
Xolve

หากมีสาธารณะคุณสามารถเชื่อมโยงข้อมูลสรุปด้านเทคนิคของ NASA (และข้อมูลการเชื่อมต่อแบบอนุกรมของกระสวยอวกาศบิตกระสวยอวกาศ) ที่คุณกำลังพูดถึงได้หรือไม่? คงจะน่าหลงใหลฉันไม่เคยเห็นอะไรแบบนั้นมาก่อน
n611x007

3
Bitwise endianness ยังเข้ามามีบทบาทในรูปแบบการบีบอัดที่ใช้การเข้ารหัส Huffman บางรูปแบบ (กล่าวคือทั้งหมด) เพื่อความสนุกสนานเป็นพิเศษ JPEG คือ "bitwise big-endian" (เช่นบิตที่สำคัญที่สุดคือบิต "ตัวแรก") และ LZ คือ "bitwise little-endian" ครั้งหนึ่งฉันเคยทำงานกับรูปแบบการบีบอัดที่เป็นกรรมสิทธิ์ซึ่งใช้ทั้งสองรูปแบบภายใต้ประทุน โอ้ยสนุก
จัง

เมื่อเริ่มต้นเป็นบิตฉันคิดว่านั่นเป็นความพยายามมานานแล้ว
Roy Falk

20

ไม่มีจำนวนเต็มที่ไม่ได้ลงชื่อใน Java จำนวนเต็มทั้งหมดได้รับการลงนามและเป็น endian ใหญ่

ทางด้าน C แต่ละไบต์จะมี tne LSB ที่จุดเริ่มต้นอยู่ทางซ้ายและ MSB ที่ส่วนท้าย

ดูเหมือนว่าคุณกำลังใช้ LSB เป็นบิตที่มีนัยสำคัญน้อยที่สุดใช่ไหม LSB มักย่อมาจากไบต์ที่มีนัยสำคัญน้อยที่สุด Endiannessไม่ได้ขึ้นอยู่กับบิต แต่อิงตามไบต์

ในการแปลงจากไบต์ที่ไม่ได้ลงชื่อเป็นจำนวนเต็ม Java:

int i = (int) b & 0xFF;

ในการแปลงจาก bit-endian 32 บิตที่ไม่ได้ลงนามในไบต์ [] เป็น Java แบบยาว (จากด้านบนของหัวของฉันไม่ได้ทดสอบ):

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

เพิ่งรู้ว่า: $ ดังนั้นฉันควรจะส่ง endian ตัวน้อยที่ไม่ได้ลงนามนี้ไปยังกระบวนการ java ของฉันเพื่ออ่านอย่างถูกต้องได้อย่างไร?
hhafez

สิ่งที่ฉันหมายถึงโดยจุดเริ่มต้นคือ lsb อยู่ที่จุดเริ่มต้นของ 4 ไบต์ (มันเป็น int 32 บิตที่ไม่ได้ลงนาม) ดังนั้นฉันจึงหมายถึงไบต์ที่มีนัยสำคัญน้อยที่สุด
hhafez

ฉันกำลังแปลงจาก C -> Java ไม่ใช่จาก Java -> C :)
hhafez

โค้ดของคุณทำงานได้ดีตราบใดที่คุณลบเซมิโคลอนหลัง 0xFF ในสามบรรทัดสุดท้าย ฉันจะแก้ไขเอง แต่นั่นเป็นการเปลี่ยนแปลงที่มีอักขระน้อยกว่า 6 ตัว
Moose Morals

1
ใช้เวลาเกือบ 8 ปี แต่ในที่สุดก็มีคนพบข้อผิดพลาดทางไวยากรณ์ ขอบคุณ @MooseMorals :)
Jonas Elfström

12

ไม่มีทางที่สิ่งนี้จะส่งผลต่อสิ่งใด ๆ ใน Java เนื่องจากไม่มีวิธี (ไม่ใช่ API โดยตรง) ในการแมปไบต์บางส่วนกับ int ใน Java โดยตรง

ทุก API ที่ทำสิ่งนี้หรือสิ่งที่คล้ายกันจะกำหนดพฤติกรรมได้ค่อนข้างแม่นยำดังนั้นคุณควรค้นหาเอกสารประกอบของ API นั้น


3
โอ้แน่ใจว่ามี คณิตศาสตร์ไบนารี (&, |, <<, ฯลฯ ) ทำงานได้ดีกับไบต์และ ints มันค่อนข้างง่ายที่จะใช้ไบต์ตามอำเภอใจและรวมเป็นจำนวนเต็ม
สมุนไพร

8
แต่ถ้าคุณทำเช่นนี้คุณยังไม่สามารถบอกได้ว่า JVM ของคุณใช้อะไรเป็นการภายใน
Darron

4
ใช่ แต่ถึงแม้ว่าคุณจะไม่ได้ทำแผนที่โดยตรง คุณกำลังใช้เลขคณิตที่ตรงตามที่คุณบอกไม่มีความคลุมเครือ ใน C คุณสามารถโยน "byte *" เป็น "long *" ได้เสมอและยกเลิกการอ้างอิง จากนั้นคุณจะต้องสนใจเกี่ยวกับความอดทน ใน Java ไม่มีวิธีที่ตรงและไม่ชัดเจนในการทำเช่นนั้น
Joachim Sauer

ฉันเห็น คุณกำลังพูดถึงนักแสดงไม่ใช่คณิตศาสตร์ไบนารี ใช่ในกรณีนี้คุณถูกต้อง
สมุนไพร

10
+1สำหรับ "ค้นหาเอกสารประกอบ" แต่หมายเหตุ:ประโยคที่ 1 ไม่ถูกต้องอีกต่อไปเนื่องจากในปัจจุบันแพ็คเกจ NIO มี ByteBuffer ซึ่งสามารถแมปไบต์กับแบบดั้งเดิมและคุณสามารถเปลี่ยนลำดับไบต์ได้ที่ไหน ดูByteBufferและByteOrder
user85421

3

ฉันจะอ่านไบต์ทีละไบต์และรวมเป็นค่ายาว ด้วยวิธีนี้คุณจะควบคุมความอดทนและกระบวนการสื่อสารมีความโปร่งใส


สนใจที่จะแสดงความคิดเห็นว่าทำไมคุณถึงโหวตฉัน?
Wouter Lievens

เพราะแม้ว่าฉันจะอ่านทีละไบต์ทีละรายการความสิ้นสุดของไบต์ที่ส่งไปจะไม่ถูกต้องดังนั้นฉันจึงต้องแปลง
hhafez

24
Endianness ของไบต์? อะไรวะเนี่ย? คำต่างๆมีความอ่อนไหวต่อ endianness แต่ละไบต์ไม่ได้
Wouter Lievens

3
@hhafez นั่นไม่เป็นความจริงไบต์ไม่มีความสิ้นหวังเท่าที่เราต้องกังวลหากคุณอ่านไบต์ทีละไบต์คุณโปรแกรมเมอร์มีหน้าที่กำหนดไบต์ไปยังตำแหน่งที่เหมาะสม นั่นคือสิ่งที่ DataInputStream ทำเพียงแค่รวบรวมไบต์เข้าด้วยกันในลักษณะ endian ขนาดใหญ่ภายใต้ประทุน
เลขที่

2
@WouterLievens: ฉันพบอุปกรณ์ I / O บางอย่าง (เช่นชิปนาฬิกาแบบเรียลไทม์) ซึ่งไม่ว่าด้วยเหตุผลใดก็ตามที่ส่งข้อมูลในรูปแบบบิตย้อนกลับ หลังจากได้รับข้อมูลจากพวกเขาจำเป็นต้องย้อนกลับบิตในแต่ละไบต์ ฉันเห็นด้วยกับคุณว่า endian-ness ของไบต์โดยทั่วไปไม่ใช่ปัญหาเว้นแต่จะต้องจัดการกับฮาร์ดแวร์ที่ออกแบบมาแปลก ๆ โดยเฉพาะ
supercat

3

ถ้ามันเหมาะกับโปรโตคอลที่คุณใช้พิจารณาใช้ DataInputStream ที่พฤติกรรมที่มีการกำหนดไว้เป็นอย่างดี


1
เขาจะทำได้ก็ต่อเมื่อโปรโตคอลของเขาใช้ความตั้งใจเดียวกัน
Wouter Lievens

ฉันแก้ไขลิงค์และเปลี่ยนให้ชี้ไปที่ Java 9 ซึ่งเป็นรุ่นปัจจุบัน API ที่เป็นปัญหาได้รับการแนะนำใน Java 1.0 แม้ว่า
Jens Bannmann

2

Java คือ 'Big-endian' ตามที่ระบุไว้ข้างต้น นั่นหมายความว่า MSB ของ int จะอยู่ทางซ้ายหากคุณตรวจสอบหน่วยความจำ (อย่างน้อยบน CPU ของ Intel) บิตเครื่องหมายยังอยู่ใน MSB สำหรับประเภทจำนวนเต็ม Java ทั้งหมด
การอ่านจำนวนเต็ม 4 ไบต์ที่ไม่ได้ลงนามจากไฟล์ไบนารีที่จัดเก็บโดยระบบ 'Little-endian' จะต้องปรับตัวเล็กน้อยใน Java readInt () ของ DataInputStream ต้องการรูปแบบ Big-endian
นี่คือตัวอย่างที่อ่านค่าที่ไม่ได้ลงชื่อสี่ไบต์ (ตามที่ 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 อาจแตกต่างกันไป
LarsH

0

java แรง endian ใหญ่จริงๆ: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.11


3
นี่เป็นเรื่องเกี่ยวกับ endianness ของคำสั่ง bytecode ไม่ใช่ endianness ของข้อมูลขณะรันไทม์
kaya3

ฉันกำลังโหวตขึ้น ตัวอย่างข้อมูลนี้byte[] bbb = ByteBuffer.allocate(4).putFloat(0.42f).array();สร้างbyteอาร์เรย์ที่ตรงกันข้ามกับสิ่งที่ฉันC/C++สร้างขึ้น ดังนั้นความพยายามที่ยิ่งใหญ่ของ Java จึงมีผลแม้ในข้อมูลขณะรันไทม์
eigenfield
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.