web-dev-qa-db-ja.com

カウントがタイプの幅よりも大きい場合、右シフトは未定義の動作ですか?

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に符号なしの型がある場合、またはE1に符号付きの型と非負の値がある場合、結果の値はE1/2 ^ E2の商の整数部分になります。E1の型が符号付きで負の値の場合、結果の値は実装によって定義されます。

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

GCCは、コードスニペットに対して次の警告を出します。res67108863です。

警告:右シフトカウント> =タイプの幅

また、GCCから発行されたアセンブリコードも確認しました。 SHRLを呼び出すだけで、SHRLのIntel命令ドキュメントでは、resはゼロではありません。

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

33
ZijingWu

ドラフトC++標準 セクション5.8シフト演算子段落1の発言(強調鉱山):

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

したがって、nsigned int32 bits以下の場合、これは未定義であり、これはまさにgccが通知する警告です。

40
Shafik Yaghmour

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

そして、0x0FFFFFFF(10進数の268435455)を4で割った値= 67108863なので、これが結果になります。

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

17
Mats Petersson