C#发生算术运算中发生溢出或下溢的解决方案
2016-12-01 16:40
447 查看
一、现象描述
在调用一个C++ Builder写的dll之后,操作另外的一个2D Chart控件后,报如下错误:Message :算术运算中发生溢出或下溢。, Source:System.Windows.Forms, 在 System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
在 System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData)
在 System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
在 System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
在 System.Windows.Forms.Application.RunDialog(Form form)
在 System.Windows.Forms.Form.ShowDialog(IWin32Window owner)
在 System.Windows.Forms.Form.ShowDialog()
二、分析
从异常现象来看,显然和浮点数的运算有关。因为dll和2D控件本身是没有源码的,无法获知到具体异常原因。因此一个自然而然的想法是,可能是dll中某些函数更改了浮点数的设置后没有复位,导致此异常出现。从网上资料看,确实也存在这种现象:
This solution is only for those guys who r working on different culture like Farsi, Urdu, Arabic and many other, When we change the culture in the .net frame work,
they call some unmanaged code(dll's) which change the floating point of the compiler and didn't set it back to its original floating point.So we change the calling sequence to set floating point back to its original floating point before transferring the control
to managed code.
为验证此想法,在调用dll中函数的前后,观察其浮点掩码的状态情况。
int status1 = _controlfp(0, 0); ......//调用dll的代码 int status2 = _controlfp(0, 0);
运行程序,获取到上述两个状态,得到:status1为0x0009001F,stauts2为0x000C0003。因此断定是组件dll更改了系统缺省的浮点掩码设置。
三、解决方案
在VS中,有一个函数,用于设置浮点异常掩码,即_controlfp。其原型为:unsigned int _controlfp( unsigned int new, unsigned int mask );
参数:new,新的控制字位值。mask,设置新的控制字位的掩码。
如果 mask
不为零,控制字的新值被设置:对于在 mask
中打开的位(即等于 1),在 new
中,对应的位用于更新控制字。
换而言之,fpcntrl
=
(fpcntrl
& ~mask
)|(new & mask
) 其中 fpcntrl
是浮点控制字。
返回值:按位返回的值指示浮点控制态。
常用的mask如下:掩码 | 十六进制值 | 常量 | 十六进制值 |
---|---|---|---|
_MCW_DN(不正常的控件) | 0x03000000 | _DN_SAVE _DN_FLUSH | 0x00000000 0x01000000 |
_MCW_EM(中断异常掩码) | 0x0008001F | _EM_INVALID _EM_DENORMAL _EM_ZERODIVIDE _EM_OVERFLOW _EM_UNDERFLOW _EM_INEXACT | 0x00000010 0x00080000 0x00000008 0x00000004 0x00000002 0x00000001 |
_MCW_IC(无限制控件) (不支持 ARM 或 x64 平台。) | 0x00040000 | _IC_AFFINE _IC_PROJECTIVE | 0x00040000 0x00000000 |
_MCW_RC(舍入控件) | 0x00000300 | _RC_CHOP _RC_UP _RC_DOWN _RC_NEAR | 0x00000300 0x00000200 0x00000100 0x00000000 |
_MCW_PC(精度控件) (不支持 ARM 或 x64 平台。) | 0x00030000 | _PC_24(24 位) _PC_53(53 位) _PC_64(64 位) | 0x00020000 0x00010000 0x00000000 |
C#应用示例:
[DllImport("msvcr70.dll", CallingConvention = CallingConvention.Cdecl)] unsafe public static extern int _controlfp(int n, int mask); internal void ResetFPCR() { const int _EM_OVERFLOW = 0x0009001F;//为原来的默认值 const int _MCW_EM = 0x000FFFFF;//设置默认值相关的掩码为1,即可设置成默认值。 _controlfp(_EM_OVERFLOW, _MCW_EM); } void Test() { ......//调用dll的代码 ResetFPCR(); }
相关文章推荐
- .Net中使用com组件后发生System.ArithmeticException异常的解决办法(Message=算术运算中发生溢出或下溢。)
- C# 连接ORACLE数据库,执行查询提示“算术运算导致溢出。”
- 算术运算的溢出行为 and 一个数内存中表示1的个数
- .NET算术运算溢出问题
- javascript算术运算溢出
- Eclipse中通过Tomcat运行JavaWeb项目发生内存溢出:java.lang.OutOfMemoryError: PermGen space 错误的解决方案
- p1-6.cpp: 测试整型数据输入输出 \ 算术运算 和 变量溢出
- C#报算术运算导致溢出的错误
- 运行窗体跳转时提示未处理System.OverflowException HResult=-2146233066 Message=算术运算导致溢出。 Source=DevExpress.U
- c# 多线程里面创建byte数组发生内存溢出异常求解
- vs报算术运算溢出的错误
- 将expression转换为数据类型int时发生算术溢出错误 解决
- (SQL)将 expression 转换为数据类型 int 时发生算术溢出错误 2种快速处理方法
- 算术运算的溢出问题
- javascript算术运算溢出
- C#游标溢出(访问数据库)解决方案。
- 解决速达软件提示将numeric转换为数据类型numeric时发生算术溢出错误问题
- 每日总结:sql 转换为int时发生算术溢出错误、DatePart()、DateAdd()、DateDiff()函数、Case when then
- 将 expression 转换为数据类型 int 时发生算术溢出
- Eclipse中通过Tomcat运行JavaWeb项目发生内存溢出:java.lang.OutOfMemoryError: PermGen space 错误的解决方案