我很驚訝沒有得到除零例外。我如何恢復?德爾福柏林10.1分部通過零例外失蹤
柏林10.1非常新安裝,新的項目,
procedure TForm1.Button1Click(Sender: TObject);
var
a: Double;
begin
a := 5/0; // No exception
ShowMessage(a.ToString); // -> 'INF'
end;
我很驚訝沒有得到除零例外。我如何恢復?德爾福柏林10.1分部通過零例外失蹤
柏林10.1非常新安裝,新的項目,
procedure TForm1.Button1Click(Sender: TObject);
var
a: Double;
begin
a := 5/0; // No exception
ShowMessage(a.ToString); // -> 'INF'
end;
a := 5/0;
表達5/0
是,在技術語言來說,一個constant expression。
常量表達式是一種表達式,編譯器可以在不執行它所在的程序的情況下對其進行評估。常量表達式包括數字;字符串;真常數;枚舉類型的值;特殊常量True,False和零;以及由這些元素完全由操作符,類型轉換和設置構造函數構建的表達式。
因爲這樣的表達式由編譯器評估,而不是在運行時評估。所以它的評估是由編譯時間規則決定的,不能受到運行時浮點單元異常掩碼的影響。
這些規則規定正值除以零等於+INF
,這是一個特殊的IEEE754值。如果將表達式更改爲至少有一個不是常量表達式的參數,那麼將在運行時對其進行評估,並且將會引發零除異常。
可以使用數學單元的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.
並且*僅*啓用一個除零除外的異常,執行如下操作:'SetExceptionMask(GetExceptionMask - [exZeroDivide]);'。 –
該回答的第一部分對於提問 –
@DavidHeffernan沒有任何影響在關於浮點異常沒有觸發的討論中,我認爲提及SetExceptionMask是相關的。當然,這可能不是OP代碼中的原因,但是這裏發佈的代碼經常被簡化得太多,真正的代碼可能使用了變量。 –
在我的柏林副本上確認。看起來它也在東京:https://community.embarcadero.com/answers/divide-by-zero-different-in-rad-studio-10-2 –
@Jerry:那是因爲表達式是一個常量表達式,不在運行時計算。至少兩個數字中的一個(紅利,除數)必須是導致異常的變量。 –
太棒了!編譯器知道如何除以0 :) – Victoria