2012-11-25 136 views
7

如何檢測D中的整數溢出? (檢查進位標誌?)檢測整數溢出

原來的例子:

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

修訂例如:

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? 
用乘法和前/後遞增

也。

+2

看看相同的問題爲C + + http://stackoverflow.com/questions/199333/best-way-to-detect-integer-overflow-in-cc –

+1

和大會http://stackoverflow.com/問題/ 3925528/x86-assembly-inc-and-dec-instruction-and-overflow-flag –

回答

5

你可以用一些內聯彙編很容易地檢查:

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 */ 

注意:你可能無法把這個功能,因爲調用該函數可以重置標誌。您可能希望在您感興趣的操作之後將它內聯。

可以使用運算符重載進行溢出的類型: http://arsdnet.net/dcode/ranged.d是一個示例。或者我認爲模塊是標準庫中的std.bigint,通過提供任意大的整數類型來避免溢出。

+0

'jo' - *跳轉溢出*?這看起來正是我所需要的。 –

+4

是的......但請注意,溢出並不會在無符號數上發生。考慮-1:11111111的二進制表示(爲簡潔起見,此處使用ubyte)。這與255相同。但處理器不知道或在意類型是否被簽名,它只是看到了數字。 255 + 1 == -1 + 1 == 0.所以這將設置進位標誌,但不是溢出標誌。所以,如果你特別使用無符號數字,你會想要jc指令 - 如果進行跳轉 - 相反。 –

+2

另一個潛在的問題是增量指令do * not *設置進位標誌....並且編譯器會優化a + = 1進入inc a,如果在編譯時已知的話。所以你可以用+ b,因爲它們是運行時的,但+ = 1或++可能會給asm檢查帶來令人驚訝的傳遞。 –

8

對於初學者,您提供的代碼甚至不會編譯,因爲尺寸小於int的所有整數運算都使用int完成。所以a + b的結果是int,int不會隱含地轉換爲ubyte,因爲這是一個縮小的轉換。如果你想將它分配給c,那麼你需要投它。

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

現在,這顯然是一個未經檢查的轉換,它會很高興的東西44c(因爲這是給定的100200值劇組的結果)。如果你想有一個檢查轉換,然後使用std.conv.to

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

這將拋出一個ConvOverflowException(這是ConvException一個子類),因爲結果將不會在請求的類型適合。

如果你想自己做一些事情,然後檢查是否有溢出,那麼你和C/C++基本上是一樣的船隻,並且沒有進位標誌或任何類型的東西。如果使用匯編代碼檢查,可能存在這樣的事情。我不知道。但是這種語言當然不能提供這樣的東西。 std.conv.to通過檢查結果並查看它是否太大或太小(取決於參數的符號和類型)來計算出結果。

+0

如何添加像add一樣的內在函數,也會返回溢出位? – Mehrdad

+0

@Mehrdad很可能有一些內部函數給你提供了與溢出有關的額外功能,但我對它們一無所知。這比我以前處理的級別要低,我不知道它們中有多少可以保證在所有體系結構中都有。 –

+0

示例代碼只是一個模擬來說明我的問題。在閒暇時用'uint'替換'ubyte'。 –