一个类型转换而引起的三级事件的一些思考

简介:

 

  前段时间出了个三级事件,查下来竟然是因为一个溢出造成的死循环,在公司出事件还是挺冒险的一件事,除了大boss要扣钱,还要给

高层一个合理的解释,如果在小公司干活,可能就算网站宕了一天估计也没事,如果在大点的公司每秒都是银子的流失,也许造成的损失就算

我们白干一二年也抵不了,所以责任心和代码意识真的很重要。

     先来看看问题代码,在这里我做了一点点的修改,代码的意思很简单,就是想获取参数num中二进制1的个数。

static void Run(long num)
        {
            int i = 1;

            long num2 = 0;

            List<int> list = new List<int>();

            while ((num2 = (long)Math.Pow(2, i - 1)) <= num)
            {
                if ((num & num2) > 0)
                {
                    list.Add(i);
                }
                i++;
            }
        }

如果这是你写的代码,你能一眼看出来问题在哪吗?我们知道long是8个字节,也就是64位二进制,又因为二进制位中最高位是符号位,所以当

是2的63次方时,显示的就是long的minvalue,所以上面的代码当i=64的时候,又因为强转成long,所以最后的结果变成了long的MinValue,

循环下去的话就会在负数的道路上越走越远,然后这个范围溢出并没有被CLR采纳,也就没有给我们抛出OverflowException,悲剧就这样

无情的发生了,问题是发生了,但是否能从这个问题上有一些思考,在基元类型的强转中,真的适合用(long),(int)这种强转模式吗?从这个例子

上我们看到这个(long)模式的强转根本就不会检测溢出,所以以后在强转中最好就不要用这种模式了,因为在.net框架下强转的方式太多了,在

我了解的范围内唯独这种没有溢出检测,可能有些人认为这种转换速度是最快的,但是又有多少人可以信誓旦旦的说我的程序绝对不会有溢出,就

算程序有溢所造成行为异常我也会负全责的?

   为了推崇非(long)强转,下面介绍一下其他的强转方式。

 

一:为了更好的理解代码,我们先来看看原始不检测的模式。

1             long i = long.MaxValue;
2             int j = (int)i;

在IL中我们可以欣喜的看到这种不检测溢出的强转还有专有的IL指令:conv.i4,他的意思就是:将位于计算堆栈顶部的值转换为 int32。

 

二:checked

    在我们学C#语言的那天起,我们就知道有一个checked,他的唯一作用就是检测溢出。如果有则抛出异常,那我们再看看它和无检测的

方式在IL中有什么不同。

1             long i = long.MaxValue;
2 
3             checked
4             {
5                 int j = (int)i;
6             }

好家伙,看似大串的代码在IL中居然也就一个指令,其实也就多了一个ovf,这个我想你也应该清楚,在转换的时候多了一个溢出检测。

如果你从性能上反驳的话,确实这个指令性能一定比无检测的慢,我想做web的应该是慢的可以接受。

 

三:Convet.ToXXX。

这个就是C#给我们专用封装转换操作的类,这个也是我写这篇博客极力推荐的,既然是我推荐的,那肯定是会有检测溢出的,下面我们来

看看代码和IL。

1             long i = long.MaxValue;
2 
3             int j = Convert.ToInt32(i);

在IL上我们看到并没有什么特殊的转换指令,那判断肯定就在Toint32方法里面了,下面的目光转移到它的源代码中去看一看。

从源代码中,我们发现原来代码如此的简洁,尤其是这个if,如果当时用了这个ToIntXXX,也许这个事件就会在测试环境被拦截了,也许某一

天,这个if就是你的最后一根救命稻草。

 

四:IConvertible接口

   在这个接口中封装了很多类型转换的方法,而且所有的基元类型都实现了它,不过没有意思的是竟然又调用了下Convert.ToXXX。。。

1             long i = 1;
2 
3             int j = ((IConvertible)i).ToInt32(null);

从上面的IL上可以看到,居然有一个box,也难怪IConvertible是引用类型,怎么可能不box呢?这个接口方法在值类型转换场景下不值得提

倡,不方便不说,还有较大的性能损失。

 

好了,总结性的话也来了。

① 无检测代码模式: 非常不提倡,总有一天会害死你了。

② checked: 这种虽然有检测,但是写起来麻烦,当然也可以在vs里面自己去设置全局检测。

③ Convert.Toxxx: 这篇就是为了提倡它而写的,所以这个重要性我就不说了,总有一天会救你于水火之中的。

④ IConvertible: 在值类型的场景下,性能最烂而且还不好coding。

相关文章
|
7月前
|
并行计算 计算机视觉 流计算
照片生成眨眼张嘴的视频软件,制作眨眼睛张嘴图软件,手机制作人脸眨眼张嘴
这是一套基于Python的人脸动画生成系统,功能完整且模块化设计。项目利用dlib与face-alignment库实现精准人脸关键点检测,结合Delaunay三角剖分技术完成图像变形
|
开发工具 Python
2024年Python最全使用Python求解方程_python解方程,2024年最新面试高分实战
2024年Python最全使用Python求解方程_python解方程,2024年最新面试高分实战
2024年Python最全使用Python求解方程_python解方程,2024年最新面试高分实战
|
存储 人工智能 监控
《鸿蒙NEXT——为人工智能应用中的用户数据保驾护航》
鸿蒙NEXT通过星盾安全架构,实现数据最小化授权与加密传输,确保用户隐私安全。用户可精准管理应用访问特定数据,避免过度收集;系统级文件加密和TLS等协议保障数据传输安全;隐私安全中心透明化管理应用行为,增强用户掌控权。鸿蒙NEXT为人工智能应用提供全方位数据安全保障,推动AI健康发展。
491 23
|
监控 UED
页面的可用性时间的计算
页面可用性时间是指网站或应用在指定时间内能够正常访问和使用的时间比例,通常以百分比表示。计算方法为:(总时间 - 故障时间) / 总时间 × 100%。高可用性是确保用户体验和业务连续性的关键指标。
在类中使用静态方法和实例方法有什么区别?
在类中合理地使用静态方法和实例方法,可以更好地组织和管理代码,提高代码的可读性、可维护性和性能,根据具体的业务需求和逻辑来选择使用哪种方法是编写高质量面向对象代码的关键。
|
关系型数据库 定位技术 Python
geopandas中拓扑错误的发现诊断与修复
geopandas中拓扑错误的发现诊断与修复
434 6
|
存储 安全 开发工具
掌握这5个Git高级命令,让你的开发效率飞速提升!
掌握这5个Git高级命令,让你的开发效率飞速提升!
|
应用服务中间件 Docker 容器
容器日志或文件提取
该步骤指导如何提取ftm服务的日志:首先选择服务并进入容器控制台,然后打包日志为ftm.tar.gz。接着,使用Xshell通过IP地址连接服务器,查找ftm容器ID,并使用docker cp命令将日志拷贝出来。再通过FTP工具将日志下载到桌面,最后从堡垒机下载日志包到本地。如果提取class文件,可直接在容器控制台路径下操作,无需打包。
|
网络虚拟化
在torch_geometric.datasets中使用Planetoid手动导入Core数据集及发生相关错误解决方案
在torch_geometric.datasets中使用Planetoid手动导入Core数据集及发生相关错误解决方案
1297 1
在torch_geometric.datasets中使用Planetoid手动导入Core数据集及发生相关错误解决方案
|
定位技术 vr&ar
Axure 3D教程:制作3D地图原型(三维世界地图)
Axure 3D教程:制作3D地图原型(三维世界地图)