Java có đọc các số nguyên trong endian nhỏ hay endian lớn không?


94

Tôi hỏi vì tôi đang gửi một luồng byte từ một quy trình C sang Java. Ở phía C, số nguyên 32 bit có LSB là byte đầu tiên và MSB là byte thứ 4.

Vì vậy, câu hỏi của tôi là: Về phía Java khi chúng ta đọc byte khi nó được gửi từ tiến trình C, endian ở phía Java là gì?

Một câu hỏi tiếp theo: Nếu endian bên Java không giống với endian đã gửi, làm cách nào để chuyển đổi giữa chúng?


1
Đây là cách ghi nhớ của tôi về điều này để tôi sẽ không quên: Java không phải là phần cứng mà thay vào đó là ảo, là ngôn ngữ của internet. Thứ tự byte mạngendian lớn . Do đó, Java là endian lớn .
truthadjustr

Câu trả lời:


66

Sử dụng thứ tự byte mạng (big endian), giống như Java sử dụng. Xem htons man cho các trình dịch khác nhau trong C.


Bây giờ tôi không ở hộp linux của mình nhưng htons có phải là một trong những lib tiêu chuẩn không?
hhafez 12/08/08

Theo h30097.www3.hp.com/docs//base_doc/DOCUMENTATION/V51_HTML/MAN/… là một phần của thư viện c tiêu chuẩn, vâng
Egil 12/12/08

1
htons có sẵn hầu như ở mọi nơi, nhưng nó không có trong ISO C.
MSalters 12/12/08

1
Nếu bạn phải sử dụng thứ gì đó khác với thứ tự byte mạng, thì bạn có thể cuộn của riêng mình với các toán tử bitwise hoặc sử dụng các phiên bản khác nhau của java.nio. Bộ đệm
Darron 12/12/08

1
Theo trang chủ của nó, nó được định nghĩa trong POSIX.1, vì vậy nó sẽ có sẵn khá nhiều ở mọi nơi. Và dường như tôi nhớ đã sử dụng nó trong Win32, vì vậy nó không chỉ trên hệ thống POSIX.
Joachim Sauer 12/08/08

47

Tôi tình cờ đến đây qua Google và nhận được câu trả lời rằng Java là một ứng dụng quan trọng .

Đọc qua các câu trả lời, tôi muốn chỉ ra rằng byte thực sự có thứ tự endian, mặc dù thật may mắn, nếu bạn chỉ xử lý các bộ vi xử lý “chính thống”, bạn có thể sẽ không bao giờ gặp phải nó như Intel, Motorola và Zilog tất cả đã đồng ý về hướng dịch chuyển của các chip UART của họ và MSB của một byte sẽ là 2**7và LSB sẽ nằm 2**0trong CPU của họ (tôi đã sử dụng ký hiệu nguồn FORTRAN để nhấn mạnh rằng thứ này cũ như thế nào :)).

Tôi đã gặp phải vấn đề này với một số dữ liệu đường xuống nối tiếp bit của Space Shuttle hơn 20 năm trước khi chúng tôi thay thế phần cứng giao diện $ 10K bằng máy tính Mac. Có một bản tóm tắt về Công nghệ của NASA đã được công bố về nó từ lâu. Tôi chỉ đơn giản sử dụng một bảng tra cứu 256 phần tử với các bit được đảo ngược ( table[0x01]=0x80v.v.) sau khi mỗi byte được chuyển vào từ dòng bit.


Cái nhìn sâu sắc! Tôi có câu hỏi này và không có câu trả lời trên web.
Xolve

nếu bất kỳ ai trong số họ là công khai, bạn có thể liên kết tóm tắt công nghệ của NASA (và dữ liệu đường xuống nối tiếp bit của tàu con thoi) mà bạn đang nói đến không? sẽ rất hấp dẫn, tôi chưa bao giờ thấy một thứ như vậy.
n611x007

3
Bitwise endianness cũng phát huy tác dụng với các định dạng nén sử dụng một số dạng mã hóa Huffman (tức là tất cả chúng). Để thêm phần thú vị, JPEG là "bitwise big-endian" (tức là bit quan trọng nhất là bit "đầu tiên") và LZ là "bitwise little-endian". Tôi đã từng làm việc trên một định dạng nén độc quyền sử dụng cả hai định dạng này. Ồ, đó là niềm vui ...
user435779

Khi mới bắt đầu, tôi đã nghĩ ĐÓ là sự quý giá trong một thời gian dài.
Roy Falk,

20

Không có số nguyên không dấu trong Java. Tất cả các số nguyên được ký và ở dạng endian lớn.

Ở phía C, mỗi byte có tne LSB ở đầu là ở bên trái và MSB ở cuối.

Có vẻ như bạn đang sử dụng LSB là ít đáng kể nhất, phải không? LSB thường là viết tắt của byte ít quan trọng nhất. Endianness không dựa trên bit mà dựa trên byte.

Để chuyển đổi từ byte không dấu thành số nguyên Java:

int i = (int) b & 0xFF;

Để chuyển đổi từ bit-endian 32 bit không dấu trong byte [] sang Java dài (từ đỉnh đầu của tôi, chưa được kiểm tra):

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

vừa nhận ra rằng: $ vậy làm cách nào tôi phải gửi endian nhỏ không dấu này đến quy trình java của mình để đọc nó một cách chính xác?
hhafez 12/08/08

whay Ý tôi là bắt đầu là lsb ở đầu 4 byte (đó là int 32 bit không dấu) vì vậy ý ​​tôi là byte ít quan trọng nhất
hhafez 12/12/08

Ngoài ra, tôi đang chuyển đổi từ C -> Java không phải từ Java -> C :)
hhafez 12/12/08

Mã của bạn hoạt động tốt, miễn là bạn bỏ dấu chấm phẩy sau 0xFF ở ba dòng cuối cùng. Tôi muốn tự mình chỉnh sửa, nhưng đó là sự thay đổi dưới 6 ký tự.
Moose Morals

1
Mất gần 8 năm nhưng cuối cùng ai đó đã phát hiện ra lỗi cú pháp. Cảm ơn @MooseMorals :)
Jonas Elfström

12

Không có cách nào điều này có thể ảnh hưởng đến bất cứ điều gì trong Java, vì không có cách nào (trực tiếp không phải API) để ánh xạ một số byte trực tiếp thành một int trong Java.

Mọi API thực hiện điều này hoặc điều gì đó tương tự đều xác định hành vi khá chính xác, vì vậy bạn nên tra cứu tài liệu của API đó.


3
Ồ chắc chắn là có. Phép toán nhị phân (&, |, <<, v.v.) hoạt động tốt trên byte và int. Khá dễ dàng để lấy các byte tùy ý và gắn chúng vào một số nguyên.
Herms 12/12/08

8
Nhưng nếu bạn làm điều này, bạn vẫn không thể biết JVM của bạn sử dụng nội bộ những gì.
Darron 12/12/08

4
Có, nhưng ngay cả khi ở đó bạn cũng không trực tiếp lập bản đồ. Bạn đang sử dụng số học thực hiện chính xác những gì bạn nói với nó, không có sự mơ hồ. Trong C, bạn luôn có thể chuyển một "byte *" thành "dài *" và hủy tham chiếu nó. Sau đó, bạn phải quan tâm đến tính đặc biệt. Trong Java, không có cách nào trực tiếp, mơ hồ để làm điều đó.
Joachim Sauer 12/08/08

Ah tôi thấy. Bạn đang nói về diễn viên, không phải toán học nhị phân. Đúng vậy, trong trường hợp đó thì bạn đúng.
Herms

10
+1 cho "tra cứu tài liệu", nhưng LƯU Ý: câu đầu tiên không còn đúng nữa vì ngày nay gói NIO cung cấp ByteBuffer có thể ánh xạ các byte thành nguyên thủy và nơi bạn có thể thay đổi thứ tự byte. Xem ByteBufferByteOrder
user85421

3

Tôi sẽ đọc từng byte một và kết hợp chúng thành một giá trị dài . Bằng cách đó, bạn kiểm soát được sự liên kết và quá trình giao tiếp diễn ra minh bạch.


Bạn muốn bình luận về lý do tại sao bạn bỏ phiếu cho tôi?
Wouter Lievens 12/12/08

bởi vì ngay cả khi tôi đọc từng byte riêng lẻ thì nội dung của byte được gửi sẽ không chính xác, vì vậy tôi sẽ cần phải chuyển đổi nó
hhafez 12/12/08

23
Độ bền của một byte? Cái quái gì thế? Các từ có nhạy cảm với endianness, các byte riêng lẻ thì không.
Wouter Lievens 19/02/09

3
@hhafez Điều đó không đúng, byte không có giá trị như chúng ta cần quan tâm nếu bạn đọc từng byte, bạn, lập trình viên có trách nhiệm gán các byte vào vị trí thích hợp. Đó chính xác là những gì DataInputStream làm, nó chỉ tập hợp các byte lại với nhau theo một cách cuối cùng lớn dưới mui xe.
nos

2
@WouterLievens: Tôi đã gặp một số thiết bị I / O (ví dụ như chip đồng hồ thời gian thực), vì bất kỳ lý do gì, gửi dữ liệu ở định dạng đảo ngược bit; sau khi nhận dữ liệu từ chúng, cần phải đảo ngược các bit trong mỗi byte. Tôi đồng ý với bạn, mặc dù vậy, việc sử dụng byte cuối cùng không phải một vấn đề, trừ khi người ta phải xử lý các phần cứng được thiết kế kỳ lạ cụ thể.
supercat

3

Nếu nó phù hợp với giao thức bạn sử dụng, hãy cân nhắc sử dụng DataInputStream, nơi hành vi được xác định rất rõ .


1
Anh ta chỉ có thể làm điều đó nếu giao thức của anh ta sử dụng cùng một mối quan hệ.
Wouter Lievens 12/12/08

Tôi đã sửa liên kết và thay đổi nó thành Java 9, bản phát hành hiện tại. Tuy nhiên, API được đề cập đã được giới thiệu trong Java 1.0.
Jens Bannmann

2

Java là 'Big-endian' như đã nói ở trên. Điều đó có nghĩa là MSB của một int nằm ở bên trái nếu bạn kiểm tra bộ nhớ (ít nhất là trên CPU Intel). Bit dấu cũng có trong MSB cho tất cả các kiểu số nguyên Java.
Việc đọc một số nguyên không dấu 4 byte từ tệp nhị phân được lưu trữ bởi hệ thống 'Little-endian' cần một chút điều chỉnh trong Java. ReadInt () của DataInputStream mong đợi định dạng Big-endian.
Đây là một ví dụ đọc một giá trị không dấu bốn byte (như được hiển thị bởi HexEdit là 01 00 00 00) thành một số nguyên có giá trị là 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;        
 }

"Ghi chú ở trên" đề cập đến điều gì? Thứ tự hiển thị các câu trả lời SO có thể khác nhau.
LarsH

0

3
Đây là về độ bền của các lệnh bytecode, không phải là độ bền của dữ liệu trong thời gian chạy.
kaya3

Tôi đang bỏ phiếu. Đoạn mã này byte[] bbb = ByteBuffer.allocate(4).putFloat(0.42f).array();tạo ra một bytemảng ngược lại với những gì tôi đã C/C++tạo. Do đó, tính bền vững lớn của Java có hiệu lực ngay cả trong dữ liệu trong thời gian chạy.
truthadjustr
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.