忽视数值类型的长度范围而造成的问题代码
在日常编程中,我们可能经常简单的处理不同数值类型,而忽视其能表示的长度范围,比如int和long,我们可能经常将这两种类型混用,然后遇到编译报错,就用强制转换来应付。但通过我最近遇到的两个代码所暴露出的问题,发现这种做法是不严谨的。
首先看代码1(java代码),某广泛使用的即时通讯SDK所声明的接口
// 返回第i个元素 public TIMElem getElement(int i) { // 实现代码省略 } // 返回元素的个数 public long getElementCount() { // 实现代码省略 }
这段代码的问题在于:取元素时下标的数值范围和元素数组的长度不一致,我们知道在java中,int表示的范围是-2^31~2^31-1,long的范围式-2^63~2^63-1,那么如果元素个数大于int能表示的最大值,则 getElement是无法取到所有的元素的。那么sdk的demo是怎么使用这个接口的呢?
List<MessageInfo> list = new ArrayList<>(); for (int i = 0; i < timMessage.getElementCount(); i++) { final MessageInfo msgInfo = new MessageInfo(); if (ele2MessageInfo(msgInfo, timMessage, timMessage.getElement(i), isGroup) != null) { list.add(msgInfo); } }
这段代码的问题在于,如果getElementCount()的值大于int的最大值,即2^31-1(虽然实际情况不可能出现这样的场景),则getElement的参数会为负数,很可能造成异常。
再看看第二个问题的代码,也是java代码
class XXXItem implements Comparable{ // 成员变量,long类型 private long mTime; public long getTime() { return mTime; } // 实现了一个用于比较大小的接口 @Override public int compareTo(@NonNull XXXItem item) { return (int) (item.getTime() - this.getTime()); } }
Comparable的用法,熟悉java的人应该都比较清楚。这里的问题就是出在compareTo上,getTime()返回值是long类型,两个long类型相减,并将结果强制转换为int,可能会造成溢出,从而违背该代码的本来初衷。其实java标准库中的Long类已经给出了比较long的方法,,可以直接调用,它实现的也很简洁。
public final class Long extends Number implements Comparable<Long> { public static int compare(long x, long y) { return (x < y) ? -1 : ((x == y) ? 0 : 1); } }
思考
关于溢出造成的不安全代码并不罕见,在《深入理解计算机系统》这本书中的2.3节就有介绍,里面还举例了FreeBSD的代码库中就曾经存在这种存在安全隐患的代码。我觉得出现这种问题的本质还是因为:计算机科学家在设计补码这种数值表示方式时,是允许溢出这种现象存在的,有些程序逻辑甚至需要溢出来实现,但程序员在开发时,忽略了溢出的存在,而仅凭直觉去写代码,从而造成了这种隐患。因此我觉得我们在日常写代码时要注意:
- 设计接口时,相同事物返回值的类型要一致。
- 不同类型数值进行比较操作或者进行强制转换赋值时,要格外小心,思考是否会有溢出的情况出现。
- 数值类型的注意问题(代码形式)
- 在代码层面上解决由于Java用有符号数值类型映射MySQL无符号数值类型而导致的数值溢出问题
- 数值类型的注意问题(代码形式)
- 分析2个代码片段(数值范围,类型转换相关)
- C语言的整型溢出问题——各变量类型的取值范围
- Java基础篇笔记(二) ---容易忽视的表达式结果的类型,求概率、几率问题
- OutputCache造成页面响应内容类型为text/vnd.wap.wml的问题
- 详解mysql int类型的长度值问题
- 有符号数据类型的范围问题--解开自己心中的迷惑
- 【Java TCP/IP Socket】TCP Socket通信中由read返回值造成的的死锁问题(含代码)
- java基本类型(数值范围):浮点的底层表示定义,float计算快一些
- 关于Hibernate操作数据库为空(数值类型)以及引起的问题的一点点总结
- 第十二篇:线程间通信中notifyAll造成的早期通知问题(含代码)
- 【PHP解法==LeetCode滑动窗口类型问题】438.找到字符串中所有字母异位词 && 209.长度最小的子数组 && 76.最小覆盖子串(Hard)
- Java基本数据类型的长度范围
- 数据类型和数值范围
- java基础之数值类型转换的问题
- 西门子plc s7 200数据长度和数值范围及格式
- 【Java并发编程】之十二:线程间通信中notifyAll造成的早期通知问题(含代码)
- 有符号整数类型的范围问题