忽视数值类型的长度范围而造成的问题代码
在日常编程中,我们可能经常简单的处理不同数值类型,而忽视其能表示的长度范围,比如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的代码库中就曾经存在这种存在安全隐患的代码。我觉得出现这种问题的本质还是因为:计算机科学家在设计补码这种数值表示方式时,是允许溢出这种现象存在的,有些程序逻辑甚至需要溢出来实现,但程序员在开发时,忽略了溢出的存在,而仅凭直觉去写代码,从而造成了这种隐患。因此我觉得我们在日常写代码时要注意:
- 设计接口时,相同事物返回值的类型要一致。
- 不同类型数值进行比较操作或者进行强制转换赋值时,要格外小心,思考是否会有溢出的情况出现。
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
白话短信协议
白话短信协议 我们都知道短信其实也是通过网络传输的,不过走的是核心网,那既然同样走的是网络,那这些数据不外乎01010...,那手机是怎么把这串01010...翻译成我们看到的文字短信的呢? 其实短信协议和我们HTTP很相似,是基于TCP/IP的协议,短信协议也包含信息头和信息体,其每个部分都有规定的含义 接下来通过白话的方式向你解释这个协议,在这之前,有两个概念先介绍一下 PDU(Protocol Data Unit): 代表我们一条短信的整个数据,也叫一个包 UDH(User Data Header): 数据头 UD(User Data): 数据体 一个PDU包含一个UDH以及一个UD,那一个PDU就是这个样子: 那接下来我们用个最常见的例子,也就是我们平时看到最多的普通文本短信为例子,挨个解释一下每个部分具体包含了哪些内容 UDH(User Data Header) 这儿也先介绍两个概念 IE(Information Element): 表示一个UDH单元 IED(IE Data): 包含一个IE的内容 IEL(Length of IE): 表示一个IED所占用的字节长度 IEI...
- 下一篇
基于统计的预警:同环比预警实现深度剖析
摘要:UAV.Monitor提供了对全维监控指标的预警功能,各类型的监控指标均可配置预警策略,当预警策略被触发后,可通过邮件、HTTP调用等方式进行通知报警,并会根据预警时间频率等对报警动作进行压制。 一、UAV预警功能简介 UAV.Monitor提供了对全维监控指标的预警功能,各类型的监控指标均可配置预警策略,当预警策略被触发后,可通过邮件、HTTP调用等方式进行通知报警,并会根据预警时间频率等对报警动作进行压制。 预警分为流式预警、统计预警以及混合预警三种。 流式预警会对采集到的每一个监控指标数据进行预警判断,达到实时预警的目的; 统计预警是对指标在固定时间段统计值的预警,通常都是定时进行预警判定; 混合预警则是将流式预警与统计预警结合进行预警。 同环比预警就属于统计预警的一种。 二、什么是同环比预警 首先介绍一下同环比的概念,同环比描述的是统计数据的增/降幅度,即某一时间段(本期)的统计结果与之前另一相同长度时间段(基期)的比较结果。同比表示的是本期与上一个同期的比较,比如今年4月与去年4月比较,今天8点到9点与昨天8点到9点比较;环比表示的是本期与上期的比较,如今年4月与今年3...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
-
Docker使用Oracle官方镜像安装(12C,18C,19C)
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS8编译安装MySQL8.0.19
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- MySQL8.0.19开启GTID主从同步CentOS8
- CentOS7,8上快速安装Gitea,搭建Git服务器
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
推荐阅读
最新文章
- CentOS7设置SWAP分区,小内存服务器的救世主
- 设置Eclipse缩进为4个空格,增强代码规范
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS6,CentOS7官方镜像安装Oracle11G
- Hadoop3单机部署,实现最简伪集群
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- CentOS7安装Docker,走上虚拟化容器引擎之路