2012-02-15 8 views
2

I持って、次のサンプルコード:ビット単位のシフト動作uint64_tを変数

uint64_t x, y; 
x = ~(0xF<<24); 
y = ~(0xFF<<24); 

結果は次のようになります。

x=0xfffffffff0ffffff 
y=0xfffff 

は誰でも違いを説明できますか? xは64ビットで計算され、yは32で計算されるのはなぜですか?

答えて

5

デフォルトの動作は32ビットです。

x=~(0xf<<24); 

このコードは、次のステップに分解することができます

int32_t a; 
a=0x0000000f; 
a<<=24; // a=0x0f000000; 
a=~a;  // a=0xf0ffffff; 
x=(uint64_t)a; // x = 0xfffffffff0ffffff; 

そして、

y = ~(0xFF<<24); 

int32_t a; 
a=0x000000ff; 
a<<=24; // a=0xff000000; 
a=~a;  // a=0x00ffffff; 
x=(uint64_t)a; // x = 0x000000000ffffff; 
+0

気楽にするために、デフォルトは(int)であれば何でも構いません。 – Lundin

+0

厳密に言えば、32ビットシステムの0xFF << 24は未定義の動作で、結果は何でもかまいません。 – Lundin

+0

私は同意できません。その行動は予測可能でなければならない。 'a'の型が 'char'の場合、0xff << 24は負の値になります。それ以外の場合、 'a'の型がshortまたはintの場合、正の値になります。 – ciphor

2

0x0f << 24intとして見た場合、それは符号拡張すなわち0x00000000_0f000000の正数、(下線が単に読みやすくするために、Cはこの構文をサポートしていない場合)への肯定的な数であるので。これはあなたが見ているものに逆さまになります。一方、負であるため、符号拡張された方法が異なります。

0xff << 24

+0

厳密には、32ビットシステムの0xFF << 24は未定義の動作で、結果は何でもかまいません。 – Lundin

0

何かが起こるかもしれないので、あなたは、あなたのプログラムの中での行動を未定義います。

  • 整数リテラル0xFのまたは0xFFではsigned intに相当するタイプint、です。この特定のプラットフォームでは、intは明らかに32ビットです。
  • 整数リテラル24も(符号付き)intです。
  • コンパイラが< <オペレーションを評価すると、両方のオペランドが(符号付き)intになるため、暗黙の型昇格は行われません。したがって、< <の結果は、int(署名済み)です。
  • 値0xF < < 24 = 0x0F000000は、負の値ではない(符号付き)intに収まるため、すべてが問題ありません。
  • 値0xFF < < 24 = 0xFF000000 は、に(符号付き)intが入りません!ここでは、未定義のビヘイビアが呼び出され、何かが起こる可能性があります。

ISO 9899:2011 6.5.7/4:

"E1 <結果< E2はE1左シフトE2ビット位置である。 ビットはゼロで満たされている空きました"。/-/

E1が符号付きタイプと非負の値を有し、E1×2E2は、結果の型で表現可能であり、 場合」、その結果の値であり、そうでない場合、動作は 未定義です。

ので< < 24 0xFFの表現を使用することはできません。その後、プログラムは自由にガベージ値を出力します。

しかし、我々は1と0x0Fの< 24に焦点を当てていることを無視した場合:

  • が0x0F000000はまだ(署名)intです。これに〜演算子が適用されます。
  • 結果は0xF0FFFFFFです。これは依然として符号付き整数です。ほとんどのシステムでは、この32ビットの16進数は2の補数で負の数になります。
  • この署名されたintは、割り当て中にuint64_t型に変換されます。これは、最初にそれを変換することによって、次に、符号付き64ビットに変換することにより、二段階で行われるが、このような

バグコーディング標準MISRA-Cが含まれている理由の符号なし64 に64を締結しましたこのような式で整数リテラルを使いこなすことを禁止するための規則の数。 MISRA-C準拠のコードでは、各整数リテラル(MISRA-C:2004 10.6)の後に接尾辞uを使用する必要があり、符号付き整数(MISRA-C:2004 12.7)でビット単位の演算を行うことはできません。

1

他のポスターがこれを行う理由を示しています。しかし、期待される結果を取得します

uint64_t x, y; 
x = ~(0xFULL<<24); 
y = ~(0xFFULL<<24); 

それともあなたがこれを行うことができます(これはしかし上記以外の任意遅い場合、私は知らない):次に

uint64_t x, y; 
x = ~(uint64_t(0xF)<<24); 
y = ~(uint64_t(0xFF)<<24); 

x = 0xfffffffff0ffffff 
y = 0xffffffff00ffffff 
関連する問題