32

私はここで完全に狂っているに違いありませんがgcc 4.7.3、私のマシンでは最もばかげた結果が得られています。私がテストしている正確なコードは次のとおりです。

#include <iostream>

using namespace std;

int main(){
  unsigned int b = 100000;
  cout << (b>>b) << endl;
  b = b >> b;
  cout << b << endl;
  b >>= b;
  cout << b << endl;
  return 0;
}

さて、それ自体で右にシフトされた数値は 0 になるはずです(整数除算、および正/符号なし) が、どういうわけかここに私の出力があります:n/(2^n) == 0n>1

100000
100000
100000

私はクレイジーですか?何が起こっている可能性がありますか?

4

2 に答える 2

49

C++ では、C と同様に、シフトはシフトされた値のサイズ (ビット単位) に制限されます。たとえば、unsigned int が 32 ビットの場合、31 を超えるシフトは未定義です。

実際には、一般的な結果として、シフト量の最下位 5 ビットが使用され、上位ビットは無視されます。これは、コンパイラがまさにそれを行うマシン命令を生成するためです (x86 の SHR など)。

この場合、シフト値は100000(10 進数) で、たまたま110000110101000002 進数です。下位 5 ビットはゼロです。したがって、実質的に 0 のシフトが得られます。ただし、これに依存するべきではありません。技術的には、あなたが見ているのは未定義の動作です。

参考文献:

C、N1570セクション 6.5.7 の場合:

右オペランドの値が負であるか、プロモートされた左オペランドの幅以上である場合、動作は未定義です。

C++ の場合、N3690セクション 5.8 "[expr.shift]":

右オペランドが負の場合、またはプロモートされた左オペランドのビット長以上の場合、動作は未定義です。

N1570 はドラフトであり、リリースされた ISO C11 標準とほぼ同じです。この節は、1989 年の ANSI C 標準以降、ほ​​とんど同じです。

N3690 は、C++ 標準の最近のドラフトです。使用するのに最適かどうかはわかりませんが、繰り返しになりますが、この条項は変更されていません。

于 2013-10-28T13:51:40.733 に答える
32

左のオペランドのビット長よりも大きくシフトすると、未定義の動作が呼び出されます。ドラフト C++ 標準セクション5.8 シフト演算子の段落1には次のように書かれています (強調鉱山):

オペランドは、整数型またはスコープなしの列挙型である必要があり、整数昇格が実行されます。結果の型は、昇格された左オペランドの型です。右オペランドが負の場合、またはプロモートされた左オペランドのビット長以上の場合、動作は未定義です。

シフト量がリテラルの場合、 と の両方がこのコードに対して警告を生成するgcc可能性があることに注意してclang ください

cout << (b>> 100000) ;

またはbconstの場合、警告gccは次のとおりです。

warning: right shift count >= width of type [enabled by default]

MSalters が質問へのコメントで指摘しているように、これは未定義の動作であるため、この警告に頼ることさえできない場合があります。これは、用語と定義セクションの未定義の動作に関する標準の注記と一致しています。

注: [...] 許容される未定義の動作の範囲は、状況を完全に無視して予測できない結果をもたらすことから、変換中またはプログラム実行中に、環境に特有の文書化された方法で動作すること (診断メッセージの発行の有無にかかわらず) にまで及びます。変換または実行 (診断メッセージの発行を伴う)。[...]

プラットフォーム固有の詳細

サンプル コードに明らかなシフトがない理由として考えられるのは、一部のプラットフォームではシフト カウントがマスクされる5 bitsためです。たとえばx86インテル® 64 および IA-32 アーキテクチャー ソフトウェア開発者マニュアルのセクションSAL/ SAR/SHL/SHR — IA-32 アーキテクチャ互換性セクションのシフトには次のように記載されています。

8086 はシフト カウントをマスクしません。ただし、他のすべての IA-32 プロセッサ (Intel 286 プロセッサ以降) は、シフト カウントを 5 ビットにマスクするため、最大カウントは 31 になります。[...]

于 2013-10-28T13:51:52.137 に答える