Во всех версиях C и С++ до 2014 года запись
1 << (CHAR_BIT * sizeof(int) - 1)
вызвало поведение undefined, поскольку сдвиг слева определяется как эквивалентный последовательному умножению на 2
, и этот сдвиг вызывает сплошное переполнение цепочки:
Результатом
E1 << E2
являетсяE1
левое смещениеE2
битовых позиций; освобожденные биты заполняются нулями. [...] ЕслиE1
имеет подписанный тип и неотрицательное значение, аE1
× 2 E2 представляется в типе результата, то это результирующее значение; в противном случае поведение undefined.
Однако в С++ 14 текст изменился для <<
, но не для умножения:
Значение
E1 << E2
- этоE1
сдвинутые слева позицииE2
; освобожденные биты заполняются нулями. [...] В противном случае, еслиE1
имеет подписанный тип и неотрицательное значение, аE1
× 2 E2 представляется в соответствующем неподписанном типе тип результата, то это значение, , преобразованное в тип результата, является результирующим значением; в противном случае поведение undefined.
Поведение теперь такое же, как для присвоения вне диапазона для подписанного типа, т.е. как описано в [conv.integral]/3:
Если тип назначения подписан, значение не изменяется, если оно может быть представлено в типе назначения (и ширине битового поля); в противном случае значение определяется реализацией.
Это означает, что он все еще не переносится для записи 1 << 31
(в системе с 32-битным int). Итак, почему это изменение было внесено в С++ 14?