Java는 리틀 엔디안 또는 빅 엔디안으로 정수를 읽습니까?


94

C 프로세스에서 Java로 바이트 스트림을 보내고 있기 때문에 묻습니다. C 쪽에서 32 비트 정수는 LSB가 첫 번째 바이트이고 MSB가 4 번째 바이트입니다.

그래서 내 질문은 : C 프로세스에서 보낸 바이트를 읽을 때 Java 측에서 Java 측에서 엔디안 이란 무엇입니까?

후속 질문 : Java 측의 엔디안이 전송 된 엔디안과 동일하지 않은 경우 어떻게 그들간에 변환 할 수 있습니까?


1
여기에 대한 내 니모닉이 있으므로 잊지 않을 것입니다. Java는 하드웨어가 아니라 가상 인 것이 인터넷의 언어입니다. 네트워크 바이트 순서빅 엔디안 . 따라서 Java는 big endian 입니다.
truthadjustr

답변:


66

어쨌든 Java가 사용하는 것과 동일한 네트워크 바이트 순서 (빅 엔디안)를 사용하십시오. C의 다른 번역가는 man htons를 참조하십시오.


나는 지금 내 리눅스 박스에 있지 않지만 htons가 표준 라이브러리 중 하나입니까?
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

47

나는 Google을 통해 여기에서 우연히 발견했고 Java가 big endian 이라는 대답을 얻었습니다 .

응답을 읽으면서 나는 바이트가 실제로 엔디안 순서를 가지고 있음을 지적하고 싶습니다. 비록 자비 롭게도“주류”마이크로 프로세서 만 다루었다면 Intel, Motorola 및 Zilog 모두와 같이 본 적이 없을 것입니다. UART 칩의 이동 방향과 바이트의 MSB가 있고 2**7LSB가 2**0CPU에 있을 것이라는 데 동의했습니다 (이 항목이 얼마나 오래되었는지 강조하기 위해 FORTRAN 전원 표기법을 사용했습니다 :)).

저는 20 년 이상 전에 우리가 $ 10K 인터페이스 하드웨어를 Mac 컴퓨터로 교체했을 때 일부 Space Shuttle 비트 직렬 다운 링크 데이터로이 문제를 겪었습니다. 오래 전에 발표 된 NASA 기술 개요가 있습니다. 나는 단순히 table[0x01]=0x80각 바이트가 비트 스트림에서 이동 한 후 비트가 반전 된 256 요소 조회 테이블을 사용했습니다 .


훌륭한 통찰력! 이 질문이 있지만 웹에서 답변이 없습니다.
Xolve 2013-08-28

공개 된 자료가 있다면, 당신이 말하는 NASA 기술 개요 (그리고 우주 왕복선 비트 직렬 다운 링크 데이터)를 연결할 수 있습니까? 매혹적 일 것입니다. 저는 그런 것을 본 적이 없습니다.
n611x007 2013

3
비트 엔디안은 또한 어떤 형태의 Huffman 인코딩 (즉, 모두)을 사용하는 압축 형식에서도 작동합니다. 재미를 더하기 위해 JPEG는 "비트 빅 엔디안"(즉, 최상위 비트가 "첫 번째"비트)이고 LZ는 "비트 리틀 엔디안"입니다. 저는 한때 두 형식을 모두 사용하는 독점 압축 형식을 작업했습니다. 오, 재미 있었어요 ...
user435779

조금씩 시작해서 오랫동안 엔디안이라고 생각했습니다.
로이 포크

20

Java에는 부호없는 정수가 없습니다. 모든 정수는 부호가 있고 빅 엔디안입니다.

C 쪽에서 각 바이트에는 시작 부분에 LSB가 있고 왼쪽에 MSB가 있습니다.

LSB를 최하위 비트로 사용하는 것 같습니까? LSB는 일반적으로 최하위 바이트를 나타냅니다. 엔디안 은 비트 기반이 아니라 바이트 기반입니다.

부호없는 바이트에서 Java 정수로 변환하려면 다음을 수행하십시오.

int i = (int) b & 0xFF;

서명되지 않은 32 비트 little-endian in byte []에서 Java long으로 변환하려면 (테스트되지 않은 내 머리 위에서) :

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

방금 깨달았습니다 : $ 그래서이 서명되지 않은 리틀 엔디안을 Java 프로세스로 보내 올바르게 읽으려면 어떻게해야합니까?
hhafez

내가 의미하는 것은 lsb가 4 바이트의 시작 부분에 있다는 것입니다 (부호없는 32 비트 int). 그래서 나는 최하위 바이트를 의미했습니다
hhafez

또한 C-> Java가 아닌
Java-

마지막 세 줄에서 0xFF 뒤에 세미콜론을 제거하면 코드가 제대로 작동합니다. 내가 직접 편집했지만 6 자 미만으로 변경되었습니다.
Moose Morals 2016 년

1
거의 8 년이 걸렸지 만 마침내 누군가 구문 오류를 발견했습니다. 감사 @MooseMorals :
조나스 Elfström

12

Java에서 일부 바이트를 직접 int로 매핑하는 (직접적인 비 API) 방법이 없기 때문에 이것이 Java의 어떤 것에 영향을 미칠 수있는 방법이 없습니다.

이를 수행하는 모든 API 또는 이와 유사한 작업은 동작을 매우 정확하게 정의하므로 해당 API의 문서를 찾아보아야합니다.


3
오 물론입니다. 이진 수학 (&, |, << 등)은 바이트와 정수에서 잘 작동합니다. 임의의 바이트를 정수에 붙이는 것은 매우 쉽습니다.
Herms

8
그러나 이렇게하면 JVM이 내부적으로 사용하는 엔디안을 알 수 없습니다.
Darron

4
예,하지만 거기에서도 직접 매핑하지 않습니다. 당신은 당신이 말한 것을 정확하게 수행하는 산술을 사용하고 있으며 모호성이 없습니다. C에서는 항상 "byte *"를 "long *"으로 캐스팅하고 역 참조 할 수 있습니다. 그런 다음 엔디안에 관심을 가져야합니다. Java에는이를 수행하는 직접적이고 모호한 방법이 없습니다.
Joachim Sauer

아, 알겠습니다. 이진 수학이 아니라 캐스트에 대해 이야기했습니다. 네, 그렇다면 당신 말이 맞습니다.
Herms

10
"문서 조회"는 +1 하지만 참고 : 현재 NIO 패키지는 바이트를 기본 형식에 매핑 할 수 있고 바이트 순서를 변경할 수있는 ByteBuffer를 제공하므로 첫 번째 문장은 더 이상 정확하지 않습니다. ByteBufferByteOrder
user85421 2011

3

바이트를 하나씩 읽고이를 값 으로 결합합니다 . 그렇게하면 엔디안을 제어 할 수 있으며 커뮤니케이션 프로세스는 투명합니다.


왜 저에게 투표를했는지 말씀해 주시겠습니까?
Wouter Lievens

왜냐하면 내가 각 바이트를 개별적으로 읽을 곳이더라도 전송 된 바이트의 endianess가 정확하지 않기 때문에 변환해야 할 것입니다
hhafez

23
바이트의 엔디안? 도대체 무슨 일이 있다는 것입니다? 단어는 엔디안에 민감하지만 개별 바이트는 민감하지 않습니다.
Wouter Lievens

3
@hhafez 사실이 아닙니다. 바이트 단위로 읽는다면 우리가 염려 할 필요가있는 한 바이트에는 엔디안이 없습니다. 프로그래머는 바이트를 적절한 위치에 할당 할 책임이 있습니다. 이것이 바로 DataInputStream이하는 일이며, 내부적으로 빅 엔디안 방식으로 바이트를 함께 조합합니다.
nos

2
@WouterLievens : 어떤 이유로 든 비트 반전 형식으로 데이터를 보내는 I / O 장치 (예 : 실시간 클럭 칩)를 만났습니다. 그들로부터 데이터를 수신 한 후, 각 바이트의 비트를 반전해야합니다. 하지만 특이하게 설계된 특정 하드웨어를 다루지 않는 한 바이트 엔디안은 일반적 으로 문제 가되지 않는다는 점에 동의합니다 .
supercat dec.

3

사용하는 프로토콜에 맞으면 동작이 매우 잘 정의 된 DataInputStream 사용을 고려하십시오 .


1
그는 그의 프로토콜이 동일한 엔디안을 사용하는 경우에만 그렇게 할 수 있습니다.
Wouter Lievens

링크를 수정하고 현재 릴리스 인 Java 9를 가리 키도록 변경했습니다. 문제의 API는 Java 1.0에서 도입되었습니다.
Jens Bannmann

2

Java는 위에서 언급 한대로 'Big-endian'입니다. 즉, 메모리를 검사하면 int의 MSB가 왼쪽에 있습니다 (최소한 Intel CPU에서). 부호 비트는 모든 Java 정수 유형에 대한 MSB에도 있습니다.
'Little-endian'시스템이 저장 한 바이너리 파일에서 부호없는 4 바이트 정수를 읽으려면 Java에서 약간의 조정이 필요합니다. DataInputStream의 readInt ()는 Big-endian 형식을 예상합니다.
다음은 4 바이트의 부호없는 값 (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

3
이것은 런타임시 데이터의 엔디안이 아니라 바이트 코드 명령어의 엔디안에 관한 것입니다.
kaya3

나는 투표하고 있습니다. 이 조각은 byte[] bbb = ByteBuffer.allocate(4).putFloat(0.42f).array();생산 된 byte나의 것의 반대 인 배열을 C/C++생성합니다. 따라서 Java 의 빅 엔디안 은 런타임의 데이터에서도 적용됩니다.
truthadjustr
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.