web-dev-qa-db-ja.com

sizeof(int)== 4の場合、1 << 31はCで明確に定義されています

この質問への回答によると

E1 << E2の結果はE1左シフトE2ビット位置;空のビットはゼロで埋められます。 E1に符号なしタイプがある場合、結果の値はE1×2です。E2、結果タイプで表現可能な最大値より1つ大きいモジュロを減らしました。 E1が符号付き型で非負の値を持ち、E1×2の場合E2は結果タイプで表現可能であり、それが結果の値です。それ以外の場合、動作は定義されていません。

これは、1 << 31が未定義であることを意味しているようです。

ただし、1 << 31を使用しても、GCCは警告を発行しません。 1 << 32に対して1つ発行します。 リンク

それで、それはどれですか?私は基準を誤解していますか? GCCには独自の解釈がありますか?

25
Ilya Lesokhin

いいえ:タイプintの値ビットが31ビットしかない場合、_1 << 31_の動作は未定義です。

_1U << 31_はOKであり、タイプ_0x80000000_に32個の値ビットがある場合は_unsigned int_と評価されます。

バイトが8ビットであるシステムでは、sizeof(int) == 4intが最大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 << 31was有効(ただし実装定義)であり、is有効(ただし実装定義)であるためです。最新のC++でも。 C90は、<<をビットシフトとして定義し、その後、符号なし型の場合、その結果は乗算の結果であると述べましたが、符号付き型の場合はそのようなことは行わなかったため、暗黙的に有効になり、一般的な表現でカバーされたままになりました。そのビット演算子には、符号付き型の実装定義の側面があります。最近のC++では、<<を対応する符号なし型に乗算するものとして定義しており、その結果は実装定義でもある符号付き型に変換されます。

C99とC11はこれを無効にしましたが(動作が未定義であると言っています)、コンパイラーはこれを拡張機能として受け入れることができます。既存のコードとの互換性のため、およびCフロントエンドとC++フロントエンド間でコードを共有するために、GCCは引き続きそうします。ただし、1つの例外があります。-fsanitize=undefinedを使用して未定義の動作を検出し、実行時にプログラムを中止できます。これは1 << 31を処理しますが、C99またはC11としてコンパイルする場合のみです。

17
user743382

他の回答/コメントで説明されているように、未定義の動作を呼び出します。ただし、GCCが診断を発行しない理由については。

実際には、左シフトの未定義の動作につながる可能性のある2つのことがあります(両方とも[6.5.7]から):

  1. 右のオペランドの値が負であるか、プロモートされた左のオペランドの幅以上の場合、動作は定義されていません。

  2. E1が符号付きタイプで非負の値を持ち、E1×2の場合E2 結果タイプで表現可能である場合、それが結果の値です。それ以外の場合、動作は定義されていません。

明らかに、GCCは最初のものを検出しますが(そうするのは簡単なので)、後者は検出しません。

9