显然,CLR通过忽略异常并返回默认值来处理浮点异常。例如,在浮点溢出的情况下,CLR返回+ Infinity,但不会引发异常。另一方面,Delphi默认会在溢出的情况下引发异常。这是由FPU异常标志控制的,你可以通过相应地设置异常标志使Delphi与CLR做同样的事情。一切都很好。
我有一个用Delphi编写的数值库,它期望溢出作为异常引发。然后它相应地处理这些边缘情况。如果没有引发异常,它就不知道该怎么做。现在,如果我在COM dll中使用此库并从托管代码调用该COM DLL,则不会将溢出作为异常引发,并且库返回不正确的结果。我通过以下代码包装对库的所有调用来解决这个问题:
var
Mask : TFPUExceptionMask;
begin
Mask := Math.SetExceptionMask([exDenormalized, exUnderflow, exPrecision]);
try
//do my calls to the library
finally
Math.SetException(Mask);
end;
这似乎有效,但我现在有一个案例,我得到一个溢出,CLR似乎接管控制,Delphi永远不会得到一个EOverflow异常。它只是没有那么远。它进入一个溢出异常循环(浮点溢出而不是Delphi生成的EOverflows)并使应用程序崩溃。
解决这个问题的唯一方法是不使用上面的掩码,找出可能存在溢出的地方,并添加一些错误处理代码。这是一个例子:
f1 := Power(X, Y);
if f1 = Infinity then
raise EOverflow.Create('Overflow');
这不太理想,因为我不太了解图书馆,无法猜测我可能会溢出的所有可能区域。但上述工作正常。
有人有这方面的经验吗?是否有可能告诉CLR退出FPU异常并让Delphi处理它们?顺便说一句,如果我从Excel VBA调用相同的COM DLL,有相同的掩码问题,但使用上面的第一个修复,即强制调用掩码,工作正常。这只是托管代码有问题。
所以这是一个例子:
我创建了一个带有单个COM对象的Delphi Active X库(DLL)。该对象有一个名为TestOverflow的方法,如下所示:
function TTestExceptions.TestOverflow : Double;
var
Mask : TArithmeticExceptionMask;
begin
Mask := GetExceptionMask;
try
Result := Power(600, 30000);
except
On EOverflow do
Result := -1;
end;
end;
然后我创建了三个客户端。一个用Delphi编写,一个用EXCEL VBA编写,一个用C#编写。每个客户都做同样的事情。创建COM对象的实例,并调用TestOverflow。
a)Delphi客户端
面具是[exDenormalized,exUnderflow,exPrecision]
抛出带有消息“浮点溢出”的异常$ C0000091,这被捕获为EOverflow异常,函数返回-1。
b)Excel客户端
面具是[exInvalidOp,exZeroDivide,exOverflow,exUnderflow,exPrecision]
不抛出异常,函数返回+ INF。
c)C#客户端
面具是[exInvalidOp,exZeroDivide,exOverflow,exUnderflow,exPrecision]
不抛出异常,函数返回+ INF。
然后我改变了函数来操作异常掩码:function TTestExceptions.TestOverflow : Double;
var
Mask : TArithmeticExceptionMask;
begin
Mask := Math.SetExceptionMask([exDenormalized, exUnderflow, exPrecision]);
try
try
Result := Power(600, 30000);
except
On EOverflow do
Result := -1;
end;
finally
Math.SetExceptionMask(Mask);
end;
end;
这次我得到了:
a)Delphi客户端
抛出带有消息“浮点溢出”的异常$ C0000091,这被捕获为EOverflow异常,函数返回-1。
b)Excel客户端
抛出带有消息“浮点溢出”的异常$ C0000091,这被捕获为EOverflow异常,函数返回-1。
c)C#客户端
抛出了带有“浮点溢出”消息的异常$ C0000091,但执行没有继续,但在该行停止,似乎卡在该行,只是继续抛出相同的异常,直到它崩溃。