2017-12-02 386 views
5

我很驚訝沒有得到除零例外。我如何恢復?德爾福柏林10.1分部通過零例外失蹤

柏林10.1非常新安裝,新的項目,

procedure TForm1.Button1Click(Sender: TObject); 
var 
    a: Double; 
begin 
    a := 5/0;      // No exception 
    ShowMessage(a.ToString);  // -> 'INF' 
end; 
+1

在我的柏林副本上確認。看起來它也在東京:https://community.embarcadero.com/answers/divide-by-zero-different-in-rad-studio-10-2 –

+6

@Jerry:那是因爲表達式是一個常量表達式,不在運行時計算。至少兩個數字中的一個(紅利,除數)必須是導致異常的變量。 –

+2

太棒了!編譯器知道如何除以0 :) – Victoria

回答

7
a := 5/0; 

表達5/0是,在技術語言來說,一個constant expression

常量表達式是一種表達式,編譯器可以在不執行它所在的程序的情況下對其進行評估。常量表達式包括數字;字符串;真常數;枚舉類型的值;特殊常量True,False和零;以及由這些元素完全由操作符,類型轉換和設置構造函數構建的表達式。

因爲這樣的表達式由編譯器評估,而不是在運行時評估。所以它的評估是由編譯時間規則決定的,不能受到運行時浮點單元異常掩碼的影響。

這些規則規定正值除以零等於+INF,這是一個特殊的IEEE754值。如果將表達式更改爲至少有一個不是常量表達式的參數,那麼將在運行時對其進行評估,並且將會引發零除異常。

4

可以使用數學單元的SetExceptionMask功能控制其浮點異常被觸發:http://docwiki.embarcadero.com/Libraries/Tokyo/en/System.Math.SetExceptionMask

要禁用所有浮點異常使用:

SetExceptionMask(exAllArithmeticExceptions); 

爲了使所有浮點異常用途:

SetExceptionMask([]); 

另請注意,在您的示例代碼中,編譯器將確定編譯時的值(因爲表達式是常量),因此無論傳遞給SetExceptionMask的值如何,都不會觸發異常。要觸發異常時,您需要一個稍微複雜一點的例子,這樣的事情:

program test; 
uses Math; 
var 
    xx,yy: double; 
begin 
SetExceptionMask([]); 
xx := 1; 
yy := 0; 
halt(round(xx/yy)); 
end. 
+0

並且*僅*啓用一個除零除外的異常,執行如下操作:'SetExceptionMask(GetExceptionMask - [exZeroDivide]);'。 –

+3

該回答的第一部分對於提問 –

+3

@DavidHeffernan沒有任何影響在關於浮點異常沒有觸發的討論中,我認爲提及SetExceptionMask是相關的。當然,這可能不是OP代碼中的原因,但是這裏發佈的代碼經常被簡化得太多,真正的代碼可能使用了變量。 –