yohhoyの日記

技術的メモをしていきたい日記

1 << 31 == ?

C++言語における符号付き整数型の左ビットシフト<<と符号ビットの関係について。

まとめ:

  • 2の補数表現が保証されたC++20現在、左ビットシフト<<は論理左シフト(logical left shift)が保証される。
  • おまけ:C++20現在、右ビットシフト>>は算術右シフト(arithmetic right shift)が保証される。
// 前提:int型==32bit幅
constexpr int x = 1 << 31;
// x == -2147483648 (== -2^{31})

C++11時点では符号反転を伴う左ビットシフト演算は未定義動作(undefined behavior)であったがnumeric_limits<T>:::min()の実装がコア定数式(core constant expression)でなくなるという問題が発覚し、C++14策定段階のCWG DR 1457にて処理系定義(implementation-defined)の振る舞いへと修正された。*1

C++20 7.6.7/p1-3より引用。

1 The shift operators << and >> group left-to-right.
 shift-expression:
   additive-expression
   shift-expression << additive-expression
   shift-expression >> additive-expression
The operands shall be of integral or unscoped enumeration type and integral promotions are performed. The type of the result is that of the promoted left operand. The behavior is undefined if the right operand is negative, or greater than or equal to the width of the promoted left operand.
2 The value of E1 << E2 is the unique value congruent to E1 × 2E2 modulo 2N, where N is the width of the type of the result. [Note: E1 is left-shifted E2 bit positions; vacated bits are zero-filled. --end note]
3. The value of E1 >> E2 is E1/2E2, rounded down. [Note: E1 is right-shifted E2 bit positions. Right-shift on signed integral types is an arithmetic right shift, which performs sign-extension. --end note]

関連URL

*1:C++17以前は、符号付き整数型が2の補数表現とは保証されておらず、その内部表現は処理系定義となっていた。