2011-02-02 59 views
25

在這個問題上的話題是如何讓VS檢查在C#中的算術溢出,並拋出一個異常:C# Overflow not Working? How to enable Overflow Checking?爲什麼你想要發生整數溢出?

一說一些奇怪的評論,並得到了upvoted多,我希望你能幫助我在這裏:

您還可以使用checked關鍵字來包裝一個語句或一組語句,以便明確檢查它們的算術溢出。設置項目範圍的財產有點冒險,因爲往往溢出是一個相當合理的期望。

我不太瞭解硬件,但知道溢出與寄存器工作方式有關。我一直認爲溢出導致未定義的行爲,應儘可能防止。 (在'正常'項目中,不寫惡意代碼)

爲什麼你會有期望溢出發生,爲什麼你不會總是阻止它,如果你有可能? (通過設置相應的編譯器選項)

+0

http://en.wikipedia.org/wiki/Integer_overflow – 2011-02-02 21:21:58

+1

您的語句「溢出會導致未定義的行爲」不正確......它的定義非常明確,特別是在整數情況下。您的陳述「我對硬件知之甚少」在這種情況下說的是......您應該閱讀一下關於二進制文件以及在機器級別如何進行加法的說明 – JoelFan 2011-02-03 05:55:37

+1

該聲明可能來自C/C++思維模式,溢出是一種「未定義的行爲」,這意味着編譯器編寫者可以做你不希望優化的事情。 CPU確實有一個定義良好的行爲並不重要,編譯器編寫者使用bignum常量表達式求值優化器,可能會檢測到它並消除代碼「它不是C/C++程序,因此我可以將其分解」。我猜,沒有人需要關心C#,因爲到時候新的硬件做不同的事情,MS已經進入了一些新的銀彈 – Rob11311 2014-06-06 13:50:43

回答

35

主要的時候,我想溢出是計算散列碼。在那裏,結果的實際數值幅度根本就不重要 - 它實際上只是一個我偶爾用算術運算操作的模式。

我們已經檢查了項目範圍內的算術打開Noda Time - 我寧願拋出一個異常,而不是返回不正確的數據。我懷疑這是溢出是非常罕見的是可取的...我承認我通常保留未經檢查的算術,僅僅因爲它是默認的。還有速度的懲罰,當然...

3

爲什麼你不能總是防止它,如果你有可能?

缺省情況下未啓用檢查算術的原因是檢查的算術比未檢查的算術慢。如果性能對你來說不是問題,那麼啓用檢查算術作爲溢出發生通常可能是錯誤的。

+0

好的,我不知道,這聽起來很合理。這仍然不能解釋爲什麼評論說「通常溢出是一個相當合理的期望」?看看它上漲的頻率(2小時內+10),他似乎並不是唯一一個有這種觀點的人? – magnattic 2011-02-02 21:25:47

+2

區別主要在於有符號算術。由於2的補碼數字的工作方式,8位11111111實際上是負1,而不是sByte.MinValue -128(正如您可能預料的那樣)。儘管這是有道理的;將-1加1應該爲零,所以將00000001加到11111111 == 00000000。這在技術上算術溢出;位於字節左端的進位位1沒有位於分配的字節中,因此丟失。然而,積分數字總是在正數和負數之間,所以這隻會在你想要的時候出錯。 – KeithS 2011-02-02 22:09:06

1

有一個關於誰佔據了優勢溢流的程序設計程序員一個經典故事:

The Story of Mel

+1

這是一個有用的答案? – BoltClock 2011-02-02 21:25:02

3

當生成HashCodes時,從一串字符說。

0

我可以成像的另一種可能情況是一個隨機數生成算法 - 在這種情況下,我們並不關心溢出情況,因爲我們只需要一個隨機數。

1

這與寄存器的工作原理沒有多大關係,因爲它只是存儲數據變量的內存限制。 (您可以溢出內存中的變量而不會溢出任何寄存器。)

但要回答您的問題,請考慮最簡單的校驗和類型。這只是所有正在檢查的數據的總和。如果校驗和溢出,那沒關係,沒有溢出的部分仍然有意義。

其他原因可能包括,即使一個無關緊要的變量可能已經溢出,您仍希望程序保持運行。

10

我一直以爲溢出導致 未定義的行爲,應防止 在可能的情況。

您可能還會對緩衝區溢出(溢出)和數值溢出之間的差異感到困惑。

當數據寫入非託管陣列的末尾時,緩衝區溢出。它可能導致未定義的行爲,例如用用戶輸入的數據覆蓋堆棧上的返回地址。緩衝區溢出在託管代碼中很難做到。

但是,數值溢出已被很好地定義。例如,如果您有一個8位寄存器,則它只能存儲2^8個值(如果無符號,則爲0到255)。所以如果你加100 + 200,你就不會得到300,而是300模256,這就是44.使用簽名類型這個故事有點複雜。位模式以類似的方式增加,但它們被解釋爲two's complement,所以添加兩個正數可以給出負數。

3

這可能與歷史上的任何技術原因一樣多。整數溢出通常被依賴於行爲的算法(特別是哈希算法)使用,效果良好。另外,大多數CPU被設計爲允許溢出,但在進程中設置一個進位位,這使得通過長於自然的字大小實現加法更容易。要在這種情況下實現已檢查的操作,將意味着如果進位標誌置位,則會添加代碼以引發異常。不是一個巨大的強加,而是編譯器編寫者可能不想在沒有選擇的情況下強迫別人。

另一種方法是默認情況下檢查,但提供一個未選中的選項。爲什麼這不可能也可以追溯到歷史。

2

您可能會期望它在測量三角洲的東西上。一些網絡設備可以保持計數器的小型化,並且可以輪詢傳輸字節的值。如果值太大,它會溢出回零。如果你經常測量它(字節/分鐘,字節/小時),它仍然給你一些有用的東西,並且當連接斷開時通常清除計數器並不重要,它們不是完全準確的。

由於賈斯汀提到緩衝區溢出是一個不同的水壺。這是您將數組的末尾寫入內存的位置,您不應該這樣做。在數字溢出中,使用相同數量的內存。在緩衝區溢出中,您使用了未分配的內存。某些語言會自動阻止緩衝區溢出。

9

用不斷遞增的計數器進行計算時。一個典型的例子是Environment.TickCount:

int start = Environment.TickCount; 
DoSomething(); 
int end = Environment.TickCount; 
int executionTime = end - start; 

如果進行了檢查,該方案具有可能性轟炸27天的Windows在啓動後。當DoComething正在運行時,TickCount在int.MaxValue之外跳動。 PerformanceCounter是另一個例子。

即使存在溢出,這些類型的計算仍會產生準確的結果。第二個例子是用來產生代表位模式的數學類型,您對精確的結果不感興趣,只是一個可重現的結果。這些例子是校驗和,哈希和隨機數。

0

整數溢出像這樣。

你有一個8位整數1111 1111,現在加1。 0000 0000,領先的1被截斷,因爲它將位於第9位。

現在假設你有一個有符號的整數,前面的位表示它是負的。所以現在你有0111 1111.給它加1,你有1000 0000,這是-128。在這種情況下,加1到127使其切換爲負值。

我非常確定溢出行爲的確定方式,但我不確定下溢。

0

所有整數運算(well加減去並相乘至少)是精確的。這只是解釋所得到的位,你需要小心。在2的補碼系統中,您可以得到模數2的正確結果。有符號和無符號之間的唯一區別是對於有符號數,最高有效位被視爲符號位。它由程序員決定什麼是合適的。顯然,對於一些你想知道溢出的計算,如果檢測到一個溢出就採取適當的行動。我個人從來沒有需要溢出檢測。我使用一個依賴於它的線性同餘隨機數發生器,即64 * 64位無符號整數乘法,我只關心最低64位,由於截斷我可以免費獲得模運算。

5

角度

整數溢出是用來測量角度優雅的工具。你有0 == 0度,0xFFFFFFFF == 359.999 ....度。它非常方便,因爲作爲32位整數,你可以添加/減去角度(350度加20度結束溢出迴繞到10度)。您也可以決定將32位整數視爲有符號(-180至180度)和無符號(0至360)。 0xFFFFFFF相當於-179.999 ...,相當於359.999 ...,這是相等的。非常優雅。