Javaは整数をリトルエンディアンまたはビッグエンディアンで読み取りますか?


94

CプロセスからJavaにバイトストリームを送信しているので、質問します。C側では、32ビット整数はLSBが最初のバイトで、MSBが4番目のバイトです。

だから私の質問は:Java側で、Cプロセスから送信されたバイトを読み取るとき、Java側のエンディアンは何ですか?

追加質問:Java側のエンディアンが送信されたエンディアンと異なる場合、どうすればそれらを変換できますか?


1
これが私のニーモニックなので、忘れないでください。Javaはハードウェアではなく仮想であり、インターネットの言語です。ネットワークバイトオーダーがあるビッグエンディアン。したがって、Javaはビッグエンディアンです。
真理調整器

回答:


66

とにかくJavaが使用するのと同じネットワークバイトオーダー(ビッグエンディアン)を使用します。Cのさまざまな翻訳者のman htonsを参照してください。


私は今Linuxボックスにいませんが、htonsは標準ライブラリの1つですか?
hhafez 2008

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はビッグエンディアンであるという私の答えを得ました。

回答を読んで、バイトには確かにエンディアン順があることを指摘したいと思いますが、「メインストリーム」のマイクロプロセッサしか扱っていない場合は、Intel、Motorola、Zilogのすべてとしてこれに遭遇することはまずありません。彼らのUARTチップのシフト方向とバイトのMSBがあり2**7、LSBが2**0彼らのCPUにあることに同意しました(私はFORTRANの電力表記を使用して、これがどれほど古いかを強調しました:))。

私がこの問題に遭遇したのは、スペースシャトルのビットシリアルダウンリンクデータを20年以上前に$ 10KのインターフェイスハードウェアをMacコンピューターに交換したときです。NASA Techブリーフがずっと前に公開されています。table[0x01]=0x80各バイトがビットストリームからシフトインされた後、ビットが反転された(など)256要素のルックアップテーブルを使用しました。


素晴らしい洞察力!私にはこの質問があり、Webには回答がありません。
Xolve 2013

それらのいずれかが公開されている場合、あなたが話しているNASAの技術概要(およびおそらくスペースシャトルビットのシリアルダウンリンクデータ)をリンクできますか?魅力的だろう、そのようなものを見たことがない。
n611x007 2013年

3
ビット単位のエンディアンは、何らかの形式のハフマンエンコーディング(つまり、それらすべて)を使用する圧縮形式でも機能します。さらに面白くするために、JPEGは「ビット単位のビッグエンディアン」(つまり、最上位ビットが「最初の」ビット)であり、LZは「ビット単位のリトルエンディアン」です。私はかつて、両方の形式を内部で使用する独自の圧縮形式に取り組みました。ああ、それは楽しかった...
user435779 14

少しずつ始めたので、それは長い間エンディアンであると思いました。
ロイフォーク2016年

20

Javaには符号なし整数はありません。すべての整数は符号付きでビッグエンディアンです。

C側では、各バイトの先頭にLSB、左側にMSBがあります。

LSBを最下位ビットとして使用しているようですね。LSBは通常、最下位バイトを表します。 エンディアンはビットベースではなくバイトベースです。

符号なしバイトからJava整数に変換するには:

int i = (int) b & 0xFF;

バイト[]の符号なし32ビットリトルエンディアンから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 2008

私が最初に意味するのは、lsbが4バイトの先頭にあるということです(符号なし32ビットintです)。
つまり、

また、私はCから変換しています-> Javaからではなく
Java-

最後の3行で0xFFの後のセミコロンを削除する限り、コードは正常に機能します。自分で編集しますが、6文字未満の変更です。
ムースモラル

1
ほぼ8年かかりましたが、最後に誰かが構文エラーを見つけました。ありがとう@MooseMorals :)
JonasElfström

12

Javaのintにいくつかのバイトを直接マップする(直接の非API)方法がないため、これがJavaの何かに影響を与える可能性はありません。

これまたは同様のことを行うすべてのAPIは動作をかなり正確に定義しているため、そのAPIのドキュメントを調べる必要があります。


3
確かにあります。バイナリ演算(&、|、<<、など)は、バイトと整数で正常に動作します。任意のバイトを受け取り、それらを整数に貼り付けるのは非常に簡単です。
Herms

8
ただし、これを行っても、JVMが内部で使用しているエンディアンを判別することはできません。
ダロン

4
はい、でも直接マッピングしていません。あなたはあなたが言うことを正確に行う算術を使用しています、曖昧さはありません。Cでは、常に「byte *」を「long *」にキャストして、それを逆参照することができます。次に、エンディアンを気にする必要があります。Javaでは、これを行うための直接的で曖昧な方法はありません。
Joachim Sauer

ああ、なるほど。あなたはバイナリ数学ではなくキャストについて話していました。ええ、その場合あなたは正しいです。
Herms

10
「ドキュメントのルックアップ」の+1ですが、注:現在、NIOパッケージはバイトをプリミティブにマップし、バイト順序を変更できるByteBufferを提供しているため、最初の文はもう正しくありません。参照のByteBufferBYTEORDER
user85421

3

私はバイトを1つずつ読み取り、それらを長い値に結合します。そうすることで、エンディアンを制御でき、通信プロセスは透過的です。


なぜあなたが私に反対票を投じているのかコメントしてください。
Wouter Lievens

なぜなら、各バイトを個別に読み取る場所があったとしても、送信されたバイトのエンディアンは正しくないため、変換する必要があります
hhafez

23
バイトのエンディアンネス?一体何なんだ?単語はエンディアンに敏感ですが、個々のバイトはそうではありません。
Wouter Lievens、

3
@hhafezそうではありません。バイトを1バイトずつ読み取る場合、バイトにエンディアンはありません。プログラマは、バイトを適切な場所に割り当てる責任があります。それはまさにDataInputStreamが行うことであり、内部でビッグエンディアンの方法でバイトを組み立てるだけです。
nos

2
@WouterLievens:何らかの理由でビット反転形式でデータを送信するI / Oデバイス(リアルタイムクロックチップなど)に遭遇しました。それらからデータを受け取った後、各バイトのビットを逆にする必要があります。ただし、奇妙に設計された特定のハードウェアを扱う必要がない限り、バイトのエンディアンネスは一般的に問題ではないことに同意します。
スーパーキャット2013

3

使用するプロトコルに適合する場合は、動作が非常に明確に定義されているDataInputStreamの使用を検討してください。


1
彼のプロトコルが同じエンディアンを使用する場合にのみ、彼はそれを行うことができます。
Wouter Lievens、

リンクを修正し、現在のリリースであるJava 9を指すように変更しました。ただし、問題のAPIはJava 1.0で導入されました。
イェンスバンマン2017年

2

上記のように、Javaは「ビッグエンディアン」です。つまり、(少なくともIntel CPUで)メモリを調べると、intのMSBが左側にあります。符号ビットは、すべてのJava整数型のMSBにもあります。
「リトルエンディアン」システムによって格納されたバイナリファイルから4バイトの符号なし整数を読み取るには、Javaで少し調整が必要です。DataInputStreamのreadInt()はビッグエンディアン形式を想定しています。
以下は、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 のビッグエンディアンは、実行時のデータでも有効になります。
TruthAdjuster
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.