使用Set8087CW,SetMXCSR和TWebBrowser屏蔽浮点异常

Cod*_*345 8 delphi exception c++builder webbrowser-control twebbrowser

由于我不时在使用TWebBrowser和TEmbeddedWB时收到"浮点除零"异常,我发现我需要屏蔽除零除异常Set8087CW或SetMXCSR.

Q1:这样做的最佳方法是什么:

  1. 在应用程序启动的早期屏蔽这些异常,再也不要再触摸它们(应用程序是多线程的)?
  2. 使用OnBeforeNavigateOnDocumentComplete事件掩盖/取消屏蔽异常?(文档加载后是否有可能发生异常?)

Q2:什么是最好的"命令"来屏蔽"除以零"而没有别的 - 如果应用程序是32位,是否需要屏蔽64位异常?

我正在使用它的应用程序,它一直可用于显示电子邮件内容的TWebBrowser控件.

此外,如果有人可以澄清 - 这是来自Microsoft的TWebBrowser控件的特定错误还是Delphi/C++ Builder和Microsoft工具之间的区别?如果我在Visual C++应用程序中托管TWebBrowser会出现如果出现除零错误会发生什么 - 它不会被转换为异常但会发生什么 - 那么Visual C++将如何处理"除以零"异常呢?

有点奇怪的是,微软在很长一段时间内没有注意到这个问题 - 也很奇怪,Embarcardero也没有注意到它.因为有效屏蔽浮点异常也会为此特定目的屏蔽您自己的程序异常.

UPDATE

经过一番检查,我的最终解决方案是

SetExceptionMask(GetExceptionMask() << exZeroDivide);
Run Code Online (Sandbox Code Playgroud)

GetExceptionMask()的默认状态返回:TFPUExceptionMask() << exDenormalized << exUnderflow << exPrecision.很明显,一些例外已被掩盖 - 这只会增加exZeroDivide掩盖的异常.

因此,现在每个除零都会导致浮点数+ INF而不是异常.我可以忍受 - 对于代码的生产版本,我将屏蔽它以避免错误,对于调试版本,它将被解除屏蔽以检测浮点除以零.

Dav*_*nan 9

假设您不需要在应用程序代码中取消屏蔽浮点异常,那么最简单的方法就是在初始化代码中的某些位置屏蔽异常.

最好的方法是:

SetExceptionMask(exAllArithmeticExceptions);
Run Code Online (Sandbox Code Playgroud)

这将在32位目标上设置8087控制字,在64位目标上设置MXCSR.你会SetExceptionMaskMath单位找到.

如果您希望在代码中取消屏蔽浮点异常,那么它会变得棘手.一种策略是在专用线程中运行浮点代码,该线程取消屏蔽异常.这当然可以工作,但如果你依赖于RTL功能Set8087CW,那就不行了SetMXCSR.请注意,控制FP单元的RTL中的所有内容都通过这些函数进行路由.例如SetExceptionMask.

问题是,Set8087CW并且SetMXCSR不是线程安全的.似乎很难相信Embarcadero可能会如此无能为力地生成在线程上下文中运行的基本例程但却无法保证线程安全.但这就是他们所做的.

令人惊讶地难以消除它们留下的混乱,并且这样做涉及相当多的代码修补.缺乏线程安全性取决于(错误)使用全局变量Default8087CWDefaultMXCSR.如果两个线程调用Set8087CWSetMXCSR同时调用,那么这些全局变量可能会将值从一个线程泄漏到另一个线程.

您可以替换Set8087CWSetMXCSR使用不会更改全局状态的版本,但遗憾的是并非那么简单.全球状态用于其他各个地方.这可能看起来不合时宜,但如果您想了解更多关于此事的信息,请阅读我在QC报告中附带的文件:http://qc.embarcadero.com/wc/qcmain.aspx?d = 107411