2012-11-25 21 views
7

Jak wykryć przepełnienie liczby całkowitej w D? (Sprawdź flagę carry?)Wykrywanie przepełnienia liczby całkowitej

oryginalny przykład:

ubyte a = 100; 
ubyte b = 200; 
ubyte c = a + b; 
// c can't represent 300; how to detect the overflow now? 

Revised przykład:

uint a = 2_000_000_000; 
uint b = 3_000_000_000; 
uint c = a + b; 
// c can't represent 5_000_000_000; how to detect the overflow now? 

także z mnożenia i pre/post-przyrostu.

+2

mają to samo pytanie dla C++ http: //stackoverflow.com/questions/199333/best-way-to-detect-integer-overflow-in-cc –

+1

i Assembly http://stackoverflow.com/ question/3925528/x86-assembly-inc-and-dec-instruction-and-overflow-flag –

Odpowiedz

5

Można go sprawdzić dość łatwo z jakimś zespołem inline:

asm { jo overflowed; } // for checking signed types 
// or 
asm { jc overflowed; } // use this for checking unsigned types 

/* continue going */ 

return; 

overflowed: 

/* do whatever to handle it */ 

Uwaga: prawdopodobnie nie da się tego w funkcji, ponieważ wywołanie funkcji można wyzerować flagę. Będziesz chciał umieścić go bezpośrednio po operacji, którą jesteś zainteresowany.

Możliwe jest stworzenie typu, który wykorzystuje przeciążenie operatora do wyrzucenia przy przepełnieniu: http://arsdnet.net/dcode/ranged.d jest jednym z przykładów. Lub myślę, że moduł jest std.bigint w standardowej bibliotece, która unika przepełnienia, oferując arbitralnie dużą liczbę całkowitą.

+0

'jo' - * przepełnienie skoku *? Wygląda dokładnie tak, jak potrzebowałem. –

+4

Tak ... ale zauważ, że przepełnienie tak naprawdę nie ma miejsca w przypadku niepodpisanych.Rozważmy binarną reprezentację -1: 11111111 (używając tutaj ubyte dla zwięzłości). To jest to samo, co 255. Ale procesor nie wie, czy typ jest podpisany, czy nie, po prostu widzi numer. 255 + 1 == -1 + 1 == 0 Tak więc ustawi flagę carry, ale nie flagę przepełnienia. Więc jeśli używasz specjalnie niepodpisanych liczb, będziesz potrzebował instrukcji jc - jump if carry - zamiast tego. –

+2

Innym potencjalnym problemem jest instrukcja inkrementacji * nie * ustawia flagę carry .... i kompilator zoptymalizuje a + = 1 do inc, jeśli jest znany podczas kompilacji. Więc jesteś w porządku dla a + b, ponieważ są to środowiska wykonawcze, ale a + = 1 lub ++ może dać zaskakujące przejście na sprawdzanie asm. –

8

Na początek kod, który podałeś, nie będzie się nawet kompilował, ponieważ cała matematyka całkowita o rozmiarach mniejszych niż int jest wykonywana z int. Zatem wynikiem a + b jest int, a int nie będzie domyślnie konwertować na ubyte, ponieważ jest to konwersja zawężająca. Jeśli chcesz go przypisać do c, musisz go przesłać.

ubyte c = cast(ubyte)(a + b); 

Teraz, to oczywiście Niesprawdzony konwersji i będzie szczęśliwie rzeczy 44 do c (ponieważ jest to wynikiem obsady danej wartości 100 i 200). Jeśli chcesz zaznaczony konwersję, a następnie użyć std.conv.to:

ubyte c = to!ubyte(a + b); 

To rzuci ConvOverflowException (która jest podklasą ConvException), ponieważ wynik nie będzie pasował do żądanego typu.

Jeśli chcesz sam wykonać rzut, a następnie sprawdzić, czy doszło do przepełnienia, to jesteś w zasadzie tą samą łodzią, co C/C++, i nie ma żadnych flag przenoszenia ani niczego podobnego. Być może takie rzeczy istnieją, jeśli sprawdzasz za pomocą kodu zespołu. Nie wiem Ale język z pewnością nie zapewnia czegoś takiego. std.conv.to oblicza go, sprawdzając wynik i sprawdzając, czy jest zbyt duży lub zbyt mały (w zależności od znaku i rodzaju argumentu).

+0

Co powiesz na dodanie elementów wewnętrznych, takich jak 'add', które również zwracają bit przepełnienia? – Mehrdad

+0

@Mehrdad Mogą istnieć pewne cechy wewnętrzne, które zapewniają dodatkową funkcjonalność związaną z przepełnieniem, ale nie wiem nic na ich temat. To o wiele niższy poziom niż kiedykolwiek, i nie wiem, ile z nich jest gwarantowanych na wszystkich architekturach. –

+0

Przykładowy kod jest tylko symulacją ilustrującą moje pytanie. Zastąp 'ubyte' przez' uint' w wolnym czasie. –

Powiązane problemy