E1 << E2の結果はE1左シフトE2ビット位置;空のビットはゼロで埋められます。 E1に符号なしタイプがある場合、結果の値はE1×2です。E2、結果タイプで表現可能な最大値より1つ大きいモジュロを減らしました。 E1が符号付き型で非負の値を持ち、E1×2の場合E2は結果タイプで表現可能であり、それが結果の値です。それ以外の場合、動作は定義されていません。
これは、1 << 31
が未定義であることを意味しているようです。
ただし、1 << 31
を使用しても、GCCは警告を発行しません。 1 << 32
に対して1つ発行します。 リンク
それで、それはどれですか?私は基準を誤解していますか? GCCには独自の解釈がありますか?
いいえ:タイプint
の値ビットが31ビットしかない場合、_1 << 31
_の動作は未定義です。
_1U << 31
_はOKであり、タイプ_0x80000000
_に32個の値ビットがある場合は_unsigned int
_と評価されます。
バイトが8ビットであるシステムでは、sizeof(int) == 4
はint
が最大31の値ビットを持つことを意味するため、1ずつ31桁シフトすることは定義されていません。逆に、_CHAR_BIT > 8
_があるシステムでは、_1 << 31
_を記述しても問題ない場合があります。
警告レベルを上げると、gcc
が警告を発行する場合があります。 _gcc -Wall -Wextra -W -Werror
_を試してください。 clang
は、同じオプションで警告を発行します。
MichaëlRoyのコメントに対処するために、_1 << 31
_は_INT_MIN
_に確実に評価されませんnot。それはあなたのシステムにこの値を与えるかもしれませんが、標準はそれを保証しません、実際、標準はこれを未定義の振る舞いとして説明します、それであなたはそれに頼ることができないだけでなく、偽のバグを避けるためにそれを避けるべきです。オプティマイザーは、潜在的な未定義の動作を日常的に利用して、コードを削除し、プログラマーの想定を破ります。
たとえば、次のコードは単純な_return 1;
_にコンパイルされる可能性があります。
_int check_shift(int i) {
if ((1 << i) > 0)
return 1;
else
return 0;
}
_
Godboltのコンパイラエクスプローラ でサポートされているコンパイラはありませんが、そうしても適合性が損なわれることはありません。
GCCがこれについて警告しない理由は、C90では1 << 31
was有効(ただし実装定義)であり、is有効(ただし実装定義)であるためです。最新のC++でも。 C90は、<<
をビットシフトとして定義し、その後、符号なし型の場合、その結果は乗算の結果であると述べましたが、符号付き型の場合はそのようなことは行わなかったため、暗黙的に有効になり、一般的な表現でカバーされたままになりました。そのビット演算子には、符号付き型の実装定義の側面があります。最近のC++では、<<
を対応する符号なし型に乗算するものとして定義しており、その結果は実装定義でもある符号付き型に変換されます。
C99とC11はこれを無効にしましたが(動作が未定義であると言っています)、コンパイラーはこれを拡張機能として受け入れることができます。既存のコードとの互換性のため、およびCフロントエンドとC++フロントエンド間でコードを共有するために、GCCは引き続きそうします。ただし、1つの例外があります。-fsanitize=undefined
を使用して未定義の動作を検出し、実行時にプログラムを中止できます。これは1 << 31
を処理しますが、C99またはC11としてコンパイルする場合のみです。
他の回答/コメントで説明されているように、未定義の動作を呼び出します。ただし、GCCが診断を発行しない理由については。
実際には、左シフトの未定義の動作につながる可能性のある2つのことがあります(両方とも[6.5.7]から):
右のオペランドの値が負であるか、プロモートされた左のオペランドの幅以上の場合、動作は定義されていません。
E1が符号付きタイプで非負の値を持ち、E1×2の場合E2 結果タイプで表現可能である場合、それが結果の値です。それ以外の場合、動作は定義されていません。
明らかに、GCCは最初のものを検出しますが(そうするのは簡単なので)、後者は検出しません。