整数を0xFF
とすると、最下位バイトのみが残ります。 たとえば、short s
の最初のバイトを取得するには、s & 0xFF
と書くことができます。 これは一般的に「マスキング」と呼ばれます。 byte1
がシングルバイト型(uint8_t
など)であるか、すでに256未満である(結果として最下位バイトを除くすべてのゼロである)場合、上位ビットはすでにゼロであるため、上位ビットをマスクする必要はありません。
符号付き型を使用している場合は、以下のtristopiaPatrick Schlüterの回答を参照してください。 ビット単位の操作を行う場合は、符号なし型のみを使用することをお勧めします。
byte1
が8ビット整数型の場合、それは無意味です-8ビットを超える場合、本質的に値の最後の8ビットが得られます:
0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 & 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 ------------------------------- 0 0 0 0 0 0 0 0 0 1 0 1 0 1 0 1
2番目の式の危険性は、byte1
の型がchar
の場合に発生します。 その場合、いくつかの実装ではsigned char
を持つことができ、評価時に符号拡張が発生します。Gcc v3.4で試してみましたが、
signed char byte1 = 0x80;signed char byte2 = 0x10;unsigned short value1 = ((byte2 << 8) | (byte1 & 0xFF));unsigned short value2 = ((byte2 << 8) | byte1);printf("value1=%hu %hx\n", value1, value1);printf("value2=%hu %hx\n", value2, value2);
は
value1=4224 1080 rightvalue2=65408 ff80 wrong!!
を出力します。結果は、byte1
とbyte2
がchar
として宣言されていても同じです。
TL;DR
マスキングは、暗黙の符号拡張を避けることです。編集:私はチェックしました、それはC++で同じ動作です。
EDIT2:要求された記号拡張の説明として。符号拡張は、Cが式を評価する方法の結果です。 Cには昇格ルールと呼ばれるルールがあります。 Cは、評価を行う前に、すべての小さな型を暗黙的にint
キャストします。 私たちの表現に何が起こるか見てみましょう:
unsigned short value2 = ((byte2 << 8) | byte1);
byte1
は、ビットパターン0xffを含む変数です。 char
がunsigned
の場合、その値は255と解釈され、signed
の場合は-128と解釈されます。 計算を行うとき、Cは値をint
サイズ(通常は16ビットまたは32ビット)に拡張します。 これは、変数がunsigned
で値255を保持する場合、その値のビットパターンはint
として0x000000ffになることを意味します。 それがsigned
の場合、ビットパターンが0xFFFFFFFFである値-128が必要です。 符号は、計算を行うために使用される一時的なサイズに拡張されました。したがって、一時的なoringは間違った結果をもたらします。
x86アセンブリでは、movsx
命令(ゼロ拡張の場合はmovzx
)で行われます。 他のCPUにはそのための他の命令がありました(6809にはSEX
がありました)。