当前位置 : 首页 » 文章分类 :  开发  »  由一个日期相关bug想到的

由一个日期相关bug想到的

在暑假用VC++做的一个工程里面,有获取系统时间并保存为字符串的一段代码,如下:

////////获得当前年月日,给全局变量strCurTime赋值///////////
CTime currenttime = CTime::GetCurrentTime();//获得当前时间
if( currenttime.GetMonth() < 10 && currenttime.GetDay() < 10 )//月份,日期都是个位数,补0
strCurTime.Format("%d0%d0%d",currenttime.GetYear(),currenttime.GetMonth(),currenttime.GetDay());
else if( currenttime.GetMonth() < 10 )//月份是个位数,日期不是个位数,月份前补0
strCurTime.Format("%d0%d%d",currenttime.GetYear(),currenttime.GetMonth(),currenttime.GetDay());
else if( currenttime.GetDay() < 10 )//月份不是个位数,日期是个位数,日期前补0
strCurTime.Format("%d%d0%d",currenttime.GetYear(),currenttime.GetMonth(),currenttime.GetDay());

这段代码有问题,恰巧在单位数月份或单位数日期时运行不会出错,在月份和日期都是两位数时运行就会出问题。
做这个工程的时候是7、8月份,当时没有问题,现在10月份拿出来一运行就崩溃。

下面详细展示了我如何由报错找到问题所在:
崩溃后提示是STREX.CPP文件的第332行出现问题,windows搜索找出STREX.CPP文件,貌似里面是字符串操作的扩展功能。找到第332行,如下:

ASSERT(nFirst + nCount <= GetData()->nDataLength);

找到此句所在的函数:CString::Mid(int nFirst, int nCount),是从字符串中截取一段的函数,想到可能是调用Mid时下标越界。
在程序原文件中查找Mid函数,看看都在哪里用到。其中一句如下:

m_EDIT_CAM = strCurTime.Left(4)+"年"+strCurTime.Mid(4,2)+"月"+strCurTime.Right(2)+"日," + m_EDIT_CAM;
//strCurTime是全局变量,表示当前年月日,格式:YYYYMMDD

想到可能是strCurTime这个字符串有问题,这个字符串是在程序初始化函数中赋值的,遂找到程序初始化函数。就找到了文章开头的那段代码,在此段代码后加一条输出语句做测试,输出strCurTime的值,发现竟然是空的。仔细看这段代码,终于恍然大悟,发现一个很弱智但又很有意思的考虑不周全导致的bug。
月份和日期都是两位数时,不属于三个判断语句中的任何一个,所以不会给strCurTime赋值。由此导致strCurTime是空字符串,再导致Mid函数越界,触发Assert,进而导致程序崩溃。

此过程学到了什么?
不是以后写代码时应该更加仔细,而是由错误一环一环向前推理,找出错误根源的能力。
因为人总会有考虑不全的时候,你再仔细还是会出错。linux的设计者Linus Torvalds在写linux内核时也留下了bug。
我觉得这类似“授之以鱼不如授之以渔”。
分析问题的能力是更重要的。
—— 2012年10月14日 masikkk
2017.7.14:整理之前笔记时顺带吐槽一下,工作2年后看之前的代码,非常惊讶这种日期补零的操作竟然还要手动写,当时真是太缺乏工程化思想了,当然要调用现成的类库啊!

上一篇 塞林格《麦田里的守望者》读后感

下一篇 后悔本科没学的东西

阅读
评论
790
阅读预计3分钟
创建日期 2012-10-14
修改日期 2017-07-14
类别
标签

页面信息

location:
protocol:
host:
hostname:
origin:
pathname:
href:
document:
referrer:
navigator:
platform:
userAgent:

评论