シフト演算子の後の値が左側のオペランドのビット数より大きい場合、結果は未定義です。左側のオペランドが符号なしの場合、右側のシフトは論理シフトであるため、上位ビットはゼロで埋められます。左側のオペランドが符号付きの場合、右シフトは論理シフトである場合とそうでない場合があります (つまり、動作は未定義です)。
誰かが上記の行の意味を説明できますか??
それらの線が何を意味するかはあまり重要ではありません、それらは実質的に正しくありません。
「シフト演算子の後の値が左側のオペランドのビット数より大きい場合、結果は未定義です。」
本当ですが、「以上」と言うべきです。5.8 / 1:
...右側のオペランドが負の場合、またはプロモートされた左側のオペランドのビット単位の長さ以上の場合、動作は未定義です。
未定義動作とは、「実行しない」ことを意味します(後述)。つまりint、システムでが32ビットの場合、次のいずれも有効に実行できません。
int a = 0; // this is OK
a >> 32; // undefined behavior
a >> -1; // UB
a << 32; // UB
a = (0 << 32); // Either UB, or possibly an ill-formed program. I'm not sure.
「左側のオペランドが符号なしの場合、右側のシフトは論理シフトであるため、上位ビットはゼロで埋められます。」
これは本当です。5.8 / 3は言う:
E1が符号なし型である場合、またはE1が符号付き型で非負の値である場合、結果はE1の商の整数部をE2の累乗の量2で割ったものになります。
それがあなたにとってもっと理にかなっているなら。2で割る、4で割る、 8で割る>>1などと同じです。正の値の2進表現では、2で除算することは、すべてのビットを1つ右に移動し、最小のビットを破棄し、最大のビットを0で埋めることと同じです。>>2>>3
「左側のオペランドが符号付きの場合、右側のシフトは論理シフトである場合とそうでない場合があります(つまり、動作は未定義です)。」
最初の部分は真実です(論理シフトである場合とそうでない場合があります。一部のコンパイラ/プラットフォームでは発生しますが、他の動作では発生しません。最も一般的な動作はそうではないと思います)。2番目の部分はfalseであり、動作は未定義ではありません。未定義の動作とは、クラッシュ、悪魔が鼻から飛び出す、ランダムな値など、あらゆることが許可されることを意味します。標準は気にしません。C ++標準で動作が未定義であると記載されている場合はたくさんありますが、これはその1つではありません。
実際、左側のオペランドが符号付きで、値が正の場合、符号なしシフトと同じように動作します。
左側のオペランドが符号付きで、値が負の場合、結果の値は実装によって定義されます。衝突したり、発火したりすることは許可されていません。実装は結果を生成する必要があり、実装のドキュメントには、結果がどうなるかを定義するのに十分な情報が含まれている必要があります。実際には、「実装のドキュメント」はコンパイラのドキュメントから始まりますが、OSやCPUの他のドキュメントを暗黙的または明示的に参照している場合があります。
再び標準から、5.8 / 3:
が符号付きタイプで負の値の場合
E1、結果の値は実装定義です。
シフトすることでそれが何を意味するのかご存知だと思います。charあなたが8ビットを扱っているとしましょう
unsigned char c;
c >> 9;
c >> 4;
signed char c;
c >> 4;
最初のシフトでは、9> 8 [aのビット数]であるため、コンパイラーは自由に実行できますchar。未定義の動作は、すべての賭けがオフになっていることを意味し、何が起こるかを知る方法はありません。2番目のシフトは明確に定義されています。左側に0が表示されます:11111111になり00001111ます。3番目のシフトは、最初のシフトと同様に未定義です。
この3番目のケースでは、の値は重要ではないことに注意してくださいc。を参照する場合signed、実際の値がゼロより大きいかどうかではなく、変数のタイプを意味します。 signed char c = 5とsigned char c = -5は両方とも署名されており、右へのシフトは未定義の動作です。
シフト演算子の後の値が左側のオペランドのビット数より大きい場合、結果は未定義です。
それは(unsigned int)x >> 33 何でもできることを意味します[1]。
左側のオペランドが符号なしの場合、右側のシフトは論理シフトであるため、上位ビットはゼロで埋められます。
それ0xFFFFFFFFu >> 4は0x0FFFFFFFu
左側のオペランドが符号付きの場合、右側のシフトは論理シフトである場合とそうでない場合があります(つまり、動作は未定義です)。
これは0xFFFFFFFF >> 4、0xFFFFFFFF(算術シフト)または0x0FFFFFFF(論理シフト)、あるいは物理法則で許可されているものであれば何でもかまいません。つまり、結果は未定義です。
[1]:32ビットの32ビットマシンint。
いくつかのコンテキストを与えるために、ここにその段落の始まりがあります:
シフト演算子もビットを操作します。左シフト演算子(<<)は、演算子の後に指定されたビット数だけ左にシフトされた演算子の左側にあるオペランドを生成します。右シフト演算子(>>)は、演算子の後に指定されたビット数だけ右にシフトされた演算子の左側にあるオペランドを生成します。
残りは説明付きです:
シフト演算子の後の値が左側のオペランドのビット数より大きい場合、結果は未定義です。
32ビット整数を使用していて、33ビットをビットシフトしようとすると、それは許可されず、結果は未定義になります。つまり、結果は何でもかまいません。または、プログラムがクラッシュする可能性があります。
左側のオペランドが符号なしの場合、右側のシフトは論理シフトであるため、上位ビットはゼロで埋められます。
これはa >> b、aがunsignedintの場合に書き込むように定義されていることを示しています。右にシフトすると、最下位ビットが削除され、他のビットが下にシフトされ、最上位ビットがゼロになります。
言い換えると:
これ:110101000101010 >> 1 になる:011010100010101
左側のオペランドが符号付きの場合、右側のシフトは論理シフトである場合とそうでない場合があります(つまり、動作は未定義です)。
実際、ここでの動作は、引用で示唆されているように未定義ではなく、a負の場合に定義され、正の場合に定義される実装であると私は信じています。aこれは、が負の整数の場合に実行a >> bするaと、さまざまなことが発生する可能性があることを意味します。どちらが得られるかを確認するには、コンパイラのドキュメントを読む必要があります。一般的な実装は、数値が正の場合はゼロにシフトし、数値が負の場合は1にシフトすることですが、移植可能なコードを記述したい場合は、この動作に依存しないでください。
シフト演算子の後の値が左側のオペランドのビット数より大きい場合、結果は未定義です。
32 ビット整数を 33 だけシフトしようとすると、結果は未定義になります。つまり、すべてゼロの場合とそうでない場合があります。
左側のオペランドが符号なしの場合、右側のシフトは論理シフトであるため、上位ビットはゼロで埋められます。
符号なしデータ型は、右シフト時にゼロでパディングされます。
それで1100 >> 1 == 0110
左側のオペランドが符号付きの場合、右シフトは論理シフトである場合とそうでない場合があります (つまり、動作は未定義です)。
データ型が署名されている場合、動作は定義されていません。符号付きデータ型は、左端のビットが正または負を示す特別な形式で格納されます。そのため、符号付き整数をシフトすると、期待どおりに動作しない場合があります。詳細については、ウィキペディアの記事を参照してください。
キーワードは「未定義」だと思います。これは、仕様が何が起こるべきかを述べていないことを意味します。このような場合、ほとんどのコンパイラは適切な処理を行いますが、一般的に動作に依存することはできません。通常、使用しているコンパイラのドキュメントに特定のケースでの動作が記載されていない限り、未定義の動作を呼び出さないようにすることをお勧めします。
最初の文は、たとえば 32 ビット値を 32 ビット以上シフトしようとすると未定義であると述べています。
2 つ目は、unsigned int を右にシフトすると、左側のビットがゼロで埋められることを示しています。
3 つ目は、signed int を右にシフトした場合、左側のビットに何が格納されるかは定義されていないことを示しています。