当任何数学运算在.net 4中产生’NaN’时,如何强制C#编译器抛出exception?
我有一个很复杂的源代码,我需要找到变量值设置为nan的确切位置。 所以我需要编译器在那时抛出一个exception。 之前已经问过这个问题。 我发现以下答案是一个很好的答案。 此代码在.net 3.5中运行良好。但是当我使用.net 4时,此解决方案无法正常工作。 即使我在调试器中启用“抛出exception时中断”,也无法在代码中找到exception。 任何的想法?
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Runtime.InteropServices; namespace ConsoleApplication2 { class Program { [System.Runtime.InteropServices.DllImport("msvcrt.dll")] public static extern uint _control87(uint a, uint b); [System.Runtime.InteropServices.DllImport("msvcrt.dll")] public static extern uint _clearfp(); static void Main(string[] args) { float zero = 0.0f - args.Length; // Want 0.0f. Fool compiler... System.Console.WriteLine("zero = " + zero.ToString()); // A NaN which does not throw exception float firstNaN = zero / 0.0f; System.Console.WriteLine("firstNaN= " + firstNaN.ToString()); // Now turn on floating-point exceptions uint empty = 0; uint cw = _control87(empty, empty); // Debugger halts on this one and complains about false signature, but continue works. System.Console.WriteLine(cw.ToString()); uint MCW_EM = 0x0008001f; // From float.h uint _EM_INVALID = 0x00000010; // From float.h (invalid corresponds to NaN // See https://www.fortran-2000.com/ArnaudRecipes/CompilerTricks.html#x86_FP cw &= ~(_EM_INVALID); _clearfp(); // Clear floating point error word. _control87(cw, MCW_EM); // Debugger halts on this one and complains about false signature, but continue works. System.Console.WriteLine(cw.ToString()); // A NaN which does throw exception float secondNaN = 0; try { // Put as much code here as you like. // Enable "break when an exception is thrown" in the debugger // for system exceptions to get to the line where it is thrown // before catching it below. secondNaN = zero / 0.0f; } catch (System.Exception ex) { _clearfp(); // Clear floating point error word. } System.Console.WriteLine("secondNaN= " + secondNaN.ToString()); } } }
发现了问题。 修改调用以使用_controlfp
而不是_control87
,然后将DllImport
更改为:
[System.Runtime.InteropServices.DllImport("msvcrt.dll", CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl)] public static extern uint _controlfp(uint a, uint b); [System.Runtime.InteropServices.DllImport("msvcrt.dll", CallingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl)] public static extern uint _clearfp();
您必须明确告诉.NET必须使用Cdecl
约定调用您的方法。 然后它工作。 下次请写完整的exception……完整的消息应该是:
对PInvoke函数’_controlfp’的调用使堆栈失衡。 这很可能是因为托管的PInvoke签名与非托管目标签名不匹配。 检查PInvoke签名的调用约定和参数是否与目标非托管签名匹配。
或者你可以作弊:-)
struct DoubleNoNan { public readonly double Value; public DoubleNoNan(double value) { if (Double.IsNaN(value)) { throw new Exception("NaN"); } this.Value = value; } public static implicit operator double(DoubleNoNan value) { return value.Value; } public static implicit operator DoubleNoNan(double value) { return new DoubleNoNan(value); } public override bool Equals(object obj) { return this.Value.Equals(obj); } public override int GetHashCode() { return this.Value.GetHashCode(); } public override string ToString() { return this.Value.ToString(); } }
然后:
DoubleNoNan dn = 0.0; dn = / 0.0;
对于float
,将Double
替换为Single
,将double
替换为float
。 操作符将由隐式强制转换提供。
显然它有其局限性(它不能用于ref
/ out
表达式,以及许多其他表达式)
你的代码似乎工作正常……我已经检查了32位和64位
上述就是C#学习教程:当任何数学运算在.net 4中产生’NaN’时,如何强制C#编译器抛出exception?分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/958131.html