In all versions of C and C++ prior to 2014, writing
1 << (CHAR_BIT * sizeof(int) - 1)
caused undefined behaviour, because left-shifting is defined as being equivalent to successive multiplication by 2
, and this shift causes signed integer overflow:
The result of
E1 << E2
isE1
left-shiftedE2
bit positions; vacated bits are filled with zeros. [...] IfE1
has a signed type and nonnegative value, andE1
× 2E2 is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined.
However in C++14 the text has changed for <<
but not for multiplication:
The value of
E1 << E2
isE1
left-shiftedE2
bit positions; vacated bits are zero-filled. [...] Otherwise, ifE1
has a signed type and non-negative value, andE1
× 2E2 is representable in the corresponding unsigned type of the result type, then that value, converted to the result type, is the resulting value; otherwise, the behavior is undefined.
The behaviour is now the same as for out-of-range assignment to signed type, i.e. as covered by [conv.integral]/3:
If the destination type is signed, the value is unchanged if it can be represented in the destination type (and bit-field width); otherwise, the value is implementation-defined.
This means it's still non-portable to write 1 << 31
(on a system with 32-bit int). So why was this change made in C++14?
The relevant issue is CWG 1457, where the justification is that the change allows
1 << 31
to be used in constant expressions:Constant expressions can't contain undefined behavior, which means that using an expression containing UB in a context requiring a constant expression makes the program ill-formed. libstdc++'s
numeric_limits::min
, for example, once failed to compile in clang due to this.