We wszystkich wersjach C i C++, przed 2014 pisaniaDlaczego 1 << 31 zmieniono tak, aby był definiowany przez implementację w C++ 14?
1 << (CHAR_BIT * sizeof(int) - 1)
spowodowane nieokreśloną problem, ponieważ lewy biegów jest określona jako równoważne kolejnych mnożenie przez 2
, a przesunięcie to powoduje ze znakiem przepełnienia:
Wynik
E1 << E2
jestE1
przesunięty w lewoE2
pozycje bitowe; puste bity są wypełnione zerami. [...] JeśliE1
ma podpisany typ i wartość nieujemną, iE1
× 2 E2 jest reprezentowalne w typie wyniku, to jest wynikową wartością; inaczej, zachowanie jest niezdefiniowane.
Jednak w C++ 14 tekst zmienił się <<
ale nie do mnożenia:
Wartość
E1 << E2
jestE1
lewo przesuniętyE2
pozycje bitów; wolne bity są wypełnione zerami. [...] Poza tym, jeśli maE1
podpisaną rodzaj i wartości nieujemne iE1
x 2 E2 się przedstawić w odpowiadające unsigned typu wynik, to wartość przekształca się typ wyniku, jest wartością wynikową; w przeciwnym razie zachowanie jest niezdefiniowane.
zachowanie jest takie same, jak dla wykorzystania zakresem przypisania podpisanych typu, czyli objęte [conv.integral]/3:
Jeżeli typ docelowy jest podpisaniu wartość jest niezmieniona, jeśli może być reprezentowana w typie docelowym (i szerokości pola bitowego); w przeciwnym razie, wartość jest zdefiniowana przez implementację.
Oznacza to, że nadal nie jest przenośny, aby napisać 1 << 31
(w systemie z 32-bitową wersją). Dlaczego ta zmiana została wprowadzona w C++ 14?
+1 Howard Hinnant [komentarze na ten temat tutaj] (http://stackoverflow.com/questions/19593938/is-left-shifting-a-negative-integer-undefined-behavior-in-c11#comment29091986_19593938), jedynym powodem, dla którego pamiętam ten komentarz jest to, że komentarz był częścią mojej inspiracji dla tego [pytania] (http://stackoverflow.com/q/21319413/1708801). –
Wyobraź sobie, że zamiast tego po prostu napisali coś w stylu: "Ograniczenia: po awansie, lewy operand E1 będzie liczbą całkowitą bez znaku". To ocaliło ludzkość od astronomicznych ilości subtelnych błędów związanych z przesunięciem. – Lundin