バイト配列を含むデータパケットを受け取り、そこから整数値を取得する必要があります。これがドキュメントの一部です。誰かが私を助けてくれますか?
これは4バイトの配列で提供されます。
1990年から2052年(6ビット)、月1から12(4ビット)、日1から31(5ビット)、時間0から23(5ビット)、分0から59(6ビット)、 0から59までの2番目(6ビット)デフォルト値:2000年1月1日12:00:00
メッセージの形式はリトルエンディアンです。
バイト配列を含むデータパケットを受け取り、そこから整数値を取得する必要があります。これがドキュメントの一部です。誰かが私を助けてくれますか?
これは4バイトの配列で提供されます。
1990年から2052年(6ビット)、月1から12(4ビット)、日1から31(5ビット)、時間0から23(5ビット)、分0から59(6ビット)、 0から59までの2番目(6ビット)デフォルト値:2000年1月1日12:00:00
メッセージの形式はリトルエンディアンです。
必要なのは、いくつかのビット演算です。まず、バイトからintを作成します。
int n = b[0] | (b[1] << 8) | (b[2] << 16) | (b[3] << 24);
次に、intをコンポーネントに切り刻みます。さて、あなたの質問は、フィールドが右から左または左から右のどちらに行くかを指定していません。その質問はエンディアンに関連していますが、同一ではありません。したがって、フィールドが左から右に移動すると仮定しましょう。
良識は左から右を示唆しています。このようにして、時間値の整数表現を比較できます。年ビットの重要性は月ビットなどよりも大きいため、2つの瞬間に対応する整数を比較すると、時系列的に正しい結果が得られます。
これがあなたの心のイメージです。これは、ビットで構成される整数変数です。
f e d c b a 9 8 7 6 5 4 3 2 1 0
-----
offset is 6, length is 3
指定された長さ(ビット単位)で、指定されたオフセット(ビット単位)でintから任意のチャンクを取得する関数を定義しましょう。
int bits(int n, int offset, int length)
{
//shift the bits rightward, so that the desired chunk is at the right end
n = n >> (31 - offset - length);
//prepare a mask where only the rightmost `length` bits are 1's
int mask = ~(-1 << length);
//zero out all bits but the right chunk
return n & mask;
}
ワンライナーだったかもしれませんが、私はそれをいくらか有益なものにしたかったのです。以下の回答の人々は、各チャンクのシフト係数とマスクを手動で指定することにより、この関数を効果的にインライン化します。
では、分解してみましょう。nが最上位のスニペットからのものであると仮定します。
int year = bits(n, 0, 6),
month = bits(n, 6, 4),
day = bits(n, 10, 5),
hour = bits(n, 15, 5),
min = bits(n, 20, 6),
sec = bits(n, 26, 6);
前のフィールドの全長を組み合わせることにより、オフセットの値を取得します。これは、フィールドが左から右に移動することを前提としています。逆の場合、オフセット値は異なります。
それは理にかなっていますか?
編集:ビットチャンクが右から左に移動する場合は、次のようになります。
int sec = bits(n, 0, 6),
min = bits(n, 6, 6),
hour = bits(n, 12, 5),
day = bits(n, 17, 5),
month = bits(n, 22, 4),
year = bits(n, 26, 6);
まず、これを整数に変換します。
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
int timestamp = ByteBuffer.wrap(byte_array).order(ByteOrder.LITTLE_ENDIAN).getInt();
次に、私はそれを分解します:
int yearCode = (timestamp >> 26) & 0b111111;
int monthCode = (timestamp >> 22) & 0b1111;
int dayCode = (timestamp >> 17) & 0b11111;
int hourCode = (timestamp >> 12) & 0b11111;
int minCode = (timestamp >> 6) & 0b111111;
int secCode = (timestamp >> 0) & 0b111111;
最初の行のマスキングと最後の行のシフトは厳密には必要ありませんが、わかりやすくするために残されています。
最後のステップは、に1900を追加することで、yearCode
これで完了です。
あなたがJava7を持っていると仮定すると、あなたはその年を次のように読むことができるはずです。
int year = 1990
+ ((b[0] & 0b1000_0000) << 5)
+ ((b[0] & 0b0100_0000) << 4)
+ ((b[0] & 0b0010_0000) << 3)
+ ((b[0] & 0b0001_0000) << 2)
+ ((b[0] & 0b0000_1000) << 1)
+ ((b[0] & 0b0000_0100));
と月として
int month = 1
+ ((b[0] & 0b1000_0010) << 3)
+ ((b[0] & 0b0100_0001) << 2)
+ ((b[1] & 0b1000_0000) << 1)
+ ((b[1] & 0b0100_0000));
他のintも同じようにさせます。
私はjava7を持っておらず、今はテストできません。間違っていないことを願っています。バイトの順序が逆になる可能性もあります。