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は、コードスニペットに対して次の警告を出します。res
は67108863
です。
警告:右シフトカウント> =タイプの幅
また、GCCから発行されたアセンブリコードも確認しました。 SHRL
を呼び出すだけで、SHRLのIntel命令ドキュメントでは、res
はゼロではありません。
つまり、GCCはIntelプラットフォームで標準の動作を実装していないということですか?
ドラフトC++標準 セクション5.8
シフト演算子段落1の発言(強調鉱山):
結果のタイプは、プロモートされた左オペランドのタイプです。 右のオペランドが負の場合、またはビット単位の長さ以上の場合の動作は未定義です。昇格された左オペランド。
したがって、nsigned intが32 bits
以下の場合、これは未定義であり、これはまさにgcc
が通知する警告です。
何が起こるかを正確に説明するには、コンパイラは34
をレジスタにロードし、次に定数を別のレジスタにロードして、これら2つのレジスタで右シフト操作を実行します。 x86プロセッサは、シフト値に対して「shiftcount%ビット」を実行します。これは、2だけ右シフトすることを意味します。
そして、0x0FFFFFFF(10進数の268435455)を4で割った値= 67108863なので、これが結果になります。
PowerPC(私は思う)などの別のプロセッサを使用している場合は、ゼロになる可能性があります。