2017-03-28 15 views
0

私はJavaで次のメソッドを使用して、バイトの4つの整数表現のセットをlongに結合します。ビットパッキングの結果がJavaで間違った値になる

public static long addBytesToInt(int x1, int x2, int x3, int x4) { 
    return ((x4 << 24) | (x3 << 16) | (x2 << 8) | (x1 & 0xFF)); 
} 

しかし、問題は、私は、例えば、以下の値でこれを呼び出すならばということである。

//1111 1111 0000 1111 0011 1100 0000 0011 = 4279188483  
addBytesToInt(3, 60, 15, 255); 

それは間違った値を返します。意図したとおりに は、私はそれを動作させるために、次のコードに変更しなければならなかったと私は理由を理解することはできません。

public static long addBytesToInt(int x1, int x2, int x3, int x4) { 
    long l = 0; 

    l = (l << 8) + x4; 
    l = (l << 8) + x3; 
    l = (l << 8) + x2; 
    l = (l << 8) + x1; 

    return l; 
} 

答えて

1

((x4 << 24) | (x3 << 16) | (x2 << 8) | (x1 & 0xFF))に問題がオペランドの種類に関係しています。 x1-x4はすべてタイプintであるため、各シフト操作の結果もタイプintです。したがって、各演算または演算の結果は、タイプintである。 x4の値が127より大きい場合、その最終のintの結果は符号ビットが設定されているため、負の数を表します。返される番号がlongに変換されると、(負の)値が保持されます。

結果のlongの値の下位32ビットがすべて正しく設定されているため、問題を解決する最も簡単な方法は、32個の上位ビットをマスクすることです。すなわち、& 0xffffffffL操作を現在の結果に適用します。

あなたの作業方法には同じことが適用されません。変数lはタイプlongであるため、すべての操作でタイプlongの結果が生成されます。オーバーフローは発生せず、符号ビットは設定されません。

+0

お返事ありがとうございます!私はC++でもほとんど同じ機能を持っていますが、それを返す前にビットをマスキングせずに作業しています。どうしてですか?私のC++関数でも戻り値をマスキングすることをお勧めしますか? – BrokenProgrammer

+0

@BrokenProgrammer、C++では、4279188483の値を*表現することさえできるように 'long'型に頼ることはできません。C++' long'は31ビット(プラス1ビット)を持つことができます。さらに、C++では、範囲外の結果を生成する符号付き型のオペランドに対してシフト演算を実行することは安全ではありません。移植性のために、あなたのJavaコードに似たC++コードには ''が含まれていて、戻り値の型が 'uint_least32_t'であることを宣言し、' uint_least32_t 'として宣言するか、シフトする前にその型にキャストしてください。 –

+0

基本的には、次のような関数を意味します:uint_least32_t addBytesToInt(uint_least32_t x1 .. - uint_least32_t x4)?また、uint_least32_tやlong intなどの型との違いは何ですか?あなたは、種類の種類を使用していますか? – BrokenProgrammer