2017-12-02 387 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代码中的原因,但是这里发布的代码经常被简化得太多,真正的代码可能使用了变量。 –