VC++不为人所知的时间编程Bug

VC++不为人所知的时间编程Bug在VS2010的时间定义文件ATLCOMTIME.INL中,原型定义如下:ATLCOMTIME_INLINE double COleDateTi

欢迎大家来到IT世界,在知识的湖畔探索吧!

VC++ 的MFC对时间的处理函数类,主要有两对:CTime和CTimeSpan与COleDateTime和COleDateTimeSpan。笔者在使用中,发现其在早期的VC++6.0版本中存在时间计算bug,如:计算2095年与2020年的时间间隔为负值,即 -1928125696秒,使得时光倒流。本文在此与大家分享微软VC++6.0 在使用CTime和CTimeSpan与COleDateTime和COleDateTimeSpan时出现的这个最大Bug。

1、先介绍VC++6.0的时间bug之一:用CTime类表示时间只能到2039年

CTime和CTimeSpan主要封装了ANSI time_t和关于time_t的Run-Time库的主要函数。CTime里面使用的成员变量是time_t类型,该类型是个long型:

#ifndef _TIME_T_DEFINED

typedef long time_t; /* time value */

#define _TIME_T_DEFINED /* avoid multiple def’s of time_t */

#endif

由于long类型的原因,所以该类只能处理2的32次方16T的时间即:4294967296秒(16进制1 00 00 00 00H,long int是4个字节,32位)

约69年的数据,所以用CTime只能处理1970年到2039年的日期。

而在VS2010中,定义为64位长度的时间值:

#ifndef _TIME64_T_DEFINED

typedef __int64 __time64_t; /* 64-bit time value */

#define _TIME64_T_DEFINED

#endif

在VS2010中,定义为2的64次方秒,即16*1TB*1TB的大小,高枕无忧了。

2、用COleDateTimeSpan类计算时间间隔(单位为秒)

MFC同时提供了COleDateTime和COleDateTimeSpan类,使用该两个类完全可以代替CTime和CTimeSpan,COleDateTime和COleDateTimeSpan类所使用的成员变量是DATE类型,该类型是个double类型,而且使用的单位是日,所以可以处理到9999年12月31日的日期时间。

COleDateTimeSpan类是用于对COleDateTime类的两个时间的时间间隔的计算,COleDateTimeSpan类使用的成员变量COleDateTimeSpan::m_span是一个double类型是用于记录两个COleDateTime::m_dt的时间差,例如:

COleDateTime t1(2020,1,1,0,0,0);

COleDateTime t2(2040,1,1,0,0,0);

COleDateTimeSpan ts=t2-t1;

CString str;

str.Format(“%f”,ts.GetTotalSeconds());

AfxMessageBox(str);

此程序段在VC++6.0及VS2010上计算,结果一致,相当精准,如下图:

VC++不为人所知的时间编程Bug

3、这是不是意味着COleDateTimeSpan类的任何成员函数,执行程序都不会有问题呢?答案是否定的!

我们先分别在VC++6.0及VS2010上运行同一段程序,用2、的方法计算2095年与2020年的时间间隔,看看结果如何。

先在vc++6.0上做一按钮控件,执行如下程序段:

VC++不为人所知的时间编程Bug

这段程序在VC++6.0上进行运算输出结果是:-1928125696秒,这个结果明显是一个溢出。时光倒流!

计算结果截图如下:

VC++不为人所知的时间编程Bug

同样一段程序,在VS2010上显示程序如下:

VC++不为人所知的时间编程Bug

程序文本与VC++6.0的完全一样,但在VC2010上进行运算输出结果是:2366861600秒

75年,完美,非常正确的一个计算结果!

计算结果截图如下:

这到底是什么原因呢?

4、答案在COleDateTimeSpan类的成员GetTotalSeconds( )的原型定义上

VC++ 6.0 在使用COleDateTimeSpan类的GetTotalSeconds( )时,函数原型为:

double GetTotalSeconds( ) const;

返回值是double类型,但是,double GetTotalSeconds( ) const

在VC++ 6.0的MFC内部的原形定义却如下:

_AFXDISP_INLINE double COleDateTimeSpan::GetTotalSeconds() const

{

ASSERT(GetStatus() == valid);

long lReturns = (long)(m_span * 24 * 60 * 60 + AFX_OLE_DATETIME_HALFSECOND);

return lReturns;

}

哈哈!原因就出在返回的LONG上!与“1、时间bug之一”一样,计算大于69年的时间(单位为秒)间隔,时间差为负值!这是VC++ 6.0 MFC的又一个时间Bug!

幸好,微软在VS2010中作了改正。

在VS2010的时间定义文件 ATLCOMTIME.INL中,原型定义如下:

ATLCOMTIME_INLINE double COleDateTimeSpan::GetTotalSeconds() const throw()

{

ATLASSERT(GetStatus() == valid);

return (double)LONGLONG((m_span + (m_span < 0 ?

-OLE_DATETIME_HALFSECOND : OLE_DATETIME_HALFSECOND)) * (24 * 60 * 60));

}

很明显,在VS 2010中返回为double类型,double的定义为8个字节,是LONG的平方,可表示2的64次方。而在VC++ 6.0中,返回还是为long类。所以在使用函数GetTotalSeconds( )的时候,VC++ 6.0计算两个时间的间隔大于69年时就会溢出,VS 2010却安然无恙!

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://itzsg.com/35162.html

(0)
上一篇 2023年 12月 9日 下午8:00
下一篇 2023年 12月 12日 上午11:23

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

联系我们YX

mu99908888

在线咨询: 微信交谈

邮件:itzsgw@126.com

工作时间:时刻准备着!

关注微信