Jak wiemy, przepełnienie liczb całkowitych ze znakiem jest niezdefiniowanym zachowaniem . Ale w cstdint
dokumentacji C ++ 11 jest coś interesującego :
typ liczby całkowitej ze znakiem o szerokości odpowiednio 8, 16, 32 i 64 bitów bez wypełniania bitów i przy użyciu dopełnienia 2 dla wartości ujemnych (podany tylko wtedy, gdy implementacja bezpośrednio obsługuje typ)
I tu jest moje pytanie: skoro średnia mówi wyraźnie, że w przypadku int8_t
, int16_t
, int32_t
a int64_t
liczby ujemne są 2 uzupełniają, to nadal przepełnienia tych typów niezdefiniowany zachowanie?
Edycja Sprawdziłem standardy C ++ 11 i C11 i oto co znalazłem:
C ++ 11, §18.4.1:
Nagłówek definiuje wszystkie funkcje, typy i makra, tak samo jak 7.20 w standardzie C.
C11, §7.20.1.1:
Nazwa typedef
intN_t
oznacza typ liczby całkowitej ze znakiem o szerokości N, bez bitów wypełniających i reprezentacją dopełnienia do dwójki. Zatemint8_t
oznacza taki typ liczby całkowitej ze znakiem o szerokości dokładnie 8 bitów.
Odpowiedzi:
Tak. Zgodnie z paragrafem 5/4 standardu C ++ 11 (w odniesieniu do dowolnego wyrażenia w ogóle):
Fakt, że dla tych typów ze znakiem użyta jest reprezentacja dopełnienia do dwójki, nie oznacza, że przy obliczaniu wyrażeń tych typów używany jest arytmetyczny modulo 2 ^ n.
Z drugiej strony, jeśli chodzi o arytmetykę bez znaku , standard wyraźnie określa, że (paragraf 3.9.1 / 4):
Oznacza to, że wynik operacji arytmetycznej bez znaku jest zawsze „ zdefiniowany matematycznie ”, a wynik zawsze mieści się w reprezentowalnym zakresie; dlatego 5/4 nie ma zastosowania. W przypisie 46 wyjaśniono to:
źródło
Tylko dlatego, że typ jest zdefiniowany do używania reprezentacji dopełnienia 2s, nie oznacza to, że przepełnienie arytmetyczne tego typu zostanie zdefiniowane.
Niezdefiniowane zachowanie przepełnienia arytmetycznego ze znakiem jest używane do włączania optymalizacji; na przykład kompilator może założyć, że jeśli
a > b
toa + 1 > b
również; nie dotyczy to arytmetyki bez znaku, w przypadku której należałoby przeprowadzić drugie sprawdzenie ze względu na możliwość, żea + 1
może się to zakończyć0
. Ponadto niektóre platformy mogą generować sygnał pułapki przy przepełnieniu arytmetycznym (patrz np. Http://www.gnu.org/software/libc/manual/html_node/Program-Error-Signals.html ); norma nadal na to pozwala.źródło
abs
. Do tych operacji, gdy działa, nie wymaga więcej instrukcji niż w przypadku podpisanej artmetyki.(int)(x+y)>z
porównałby opakowany wynik), a także pozwoliłoby programistom pisaćx+y>z
w przypadkach, w których byłoby dopuszczalne, aby kod dawał 0 lub 1 w przypadku przepełnienia, pod warunkiem, że nie ma innych skutków ubocznych . Jeśli 0 lub 1 byłoby równie akceptowalnym wynikiem, pozwolenie programiście na napisanie tego zamiast jednego z nich(long)x+y>z
lub(int)((unsigned)x+y)>z
pozwoliłoby kompilatorom na wybranie jednej z ostatnich funkcji, która byłaby tańsza w danym kontekście [każda byłaby w niektórych przypadkach tańsza].Tak bym się założył.
Ze standardowej dokumentacji (str. 4 i 5):
źródło