ホームページ >バックエンド開発 >C++ >C の右シフト演算子 (`>>`) が 32 ビットでシフトすると予期しない結果が生じるのはなぜですか?

C の右シフト演算子 (`>>`) が 32 ビットでシフトすると予期しない結果が生じるのはなぜですか?

DDD
DDDオリジナル
2024-10-25 10:17:02455ブラウズ

C で

Why does the right shift operator (`>>`) を 32 ビットシフトすると予期しない結果が発生しますか?
C で >`) を 32 ビットシフトすると予期しない結果が発生しますか? " />

右シフト演算子の予期しない動作 (1 >> 32)

プログラミングの分野では、右シフト演算子 (>> ) は、ビット単位の演算、特に整数を 2 のべき乗で除算するためによく使用されます。ただし、次の C コードで示されているように、大きな値でシフトすると、奇妙な動作が発生する可能性があります。

<code class="cpp">int foo(int a, int b) {
   return a >> b;
}

int bar(uint64_t a, int b) {
   return a >> b;
}

int main() {
    std::cout << "foo(1, 32): " << foo(1, 32) << std::endl;
    std::cout << "bar(1, 32): " << bar(1, 32) << std::endl;
    std::cout << "1 >> 32: " << (1 >> 32) << std::endl; //warning here
    std::cout << "(int)1 >> (int)32: " << ((int)1 >> (int)32) << std::endl; //warning here
}

foo(1, 32): 1 // Should be 0
bar(1, 32): 0
1 >> 32: 0
(int)1 >> (int)32: 0</code>

これらの結果の背後にある理論的根拠は、CPU とコンパイラの内部動作にあります。

foo() の動作Function

foo() 関数では、シフト操作がキャストなしで実行され、多くのアーキテクチャでは論理右シフトが > として実装されます。したがって、foo(1, 32) は 1 > (32 % 32) となり、結果は 1 になります。

64 ビット整数へのキャストが重要なのはなぜですか?

bar() 関数では、64 ビット符号なし整数が提供され、結果が保証されます。 b (32) はオペランドのビット数 (64) より小さいため、0 になります。ただし、b を 64 に変更すると、結果は予測不能になり、依然として 1 が得られる可能性があります。

コンパイラの最適化

1 の場合>> 32 と (int)1 >> (int)32 の場合、コンパイラはコンパイル時にこれらの定数式を最適化します。標準では、カウントが負の場合、またはオペランドの長さ以上の場合の右シフトの未定義の動作が指定されています。 32 はオペランドの長さを超えているため、コンパイラは結果を判断できず、安全なフォールバックとして 0 を出力します。

CPU 固有の動作

右シフトの実装動作は CPU ごとに異なる場合があります。 x86/x86-64 アーキテクチャでは、論理右シフトは事実上 >> です。 (b % 32 または 64)、モードに応じて異なります。ただし、ARM プロセッサでは、右シフト演算は 32 以上のシフトに対してゼロを保証します。

結論

右シフト演算子を使用する場合、特にシフト数がオペランドの長さを超える場合、潜在的な未定義の動作を考慮します。 64 ビット整数などのより広い整数型にキャストすると、異なる CPU やコンパイラ間で一貫した結果を保証できます。

以上がC の右シフト演算子 (`>>`) が 32 ビットでシフトすると予期しない結果が生じるのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。