37

C++標準を確認しました。次のコードは未定義の動作であってはならないようです:

unsigned int val = 0x0FFFFFFF;
unsigned int res = val >> 34;  // res should be 0 by C++ standard,
                               // but GCC gives warning and res is 67108863

そして標準から:

E1 >> E2 の値は、E1 を右シフトした E2 ビット位置です。E1 が unsigned 型の場合、または E1 が signed 型で負でない値の場合、結果の値は E1/2^E2 の商の整数部分です。E1 に符号付きの型と負の値がある場合、結果の値は実装定義です。

標準では、34 は負の数ではないため、変数resは 0 になります。

resGCCは、コード スニペットに対して次の警告を表示します67108863

警告: 右シフト数 >= 型の幅

また、GCC によって出力されたアセンブリ コードも確認しました。を呼び出すだけでSHRL、SHRL の Intel 命令ドキュメントresは ZERO ではありません。

ということは、GCC は Intel プラットフォームで標準の動作を実装していないということですか?

4

2 に答える 2

46

段落1のセクションShift 演算子ドラフト C++ 標準には、次のように書かれています (強調鉱山):5.8

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

したがって、unsigned int32 bits以下の場合、これは未定義です。これは、まさにgccあなたに与えられている警告です。

于 2013-09-20T13:43:49.537 に答える
19

何が起こるかを正確に説明するには: コンパイラは34レジスタにロードし、次に定数を別のレジスタにロードし、これら 2 つのレジスタで右シフト演算を実行します。x86 プロセッサは、シフト値に対して "shiftcount % ビット" を実行します。つまり、2 だけ右にシフトします。

0x0FFFFFFF (10 進数で 268435455) を 4 = 67108863 で割った結果が表示されます。

たとえば、PowerPC (私が思うに) などの別のプロセッサを使用している場合は、ゼロになる可能性があります。

于 2013-09-20T13:54:02.070 に答える