1 现象:问题描述
A局点某个IUSER版本上网后,IUSERBILL批量处理程序,不能每天根据basetab_pps表号码刷新msisdn号码清单。
2 关键过程:根本原因分析
经定位,出现问题的代码如下:
int TMsisdnList::GetMsisdn(TChainNode* &pCurNode, int &handle, char* pMsisdn)
{
time_t now = 0;
struct tm *tf;
struct tm *lo;
int ret = 0;
HMSISDN tMsisdn;
// 当前时间与m_LastOpenTime相比跨天,重新初始化list
(int)time( &now );
if( ret == -1 )
{
WriteLog("TMsisdnList::GetMsisdn():failed to get system time.\n");
return -1;
}
tf = localtime( &now );
lo = localtime( &m_LastOpenTime );
if(lo->tm_mday != tf->tm_mday)
{
InitChain();
}
…
}
问题出在红色代码:调用localtime后,lo和tf指向同一个地址空间。
系统函数 struct tm *localtime(const time_t *timer);
返回的是一个指向tm 结构的指针,也就是指向某个变量(这个变量是localtime系统调用使用的内部 static变量)。再调用一次此函数后,这个静态变量的值被修改了,而原来的指针tm * tf指向的是这个变量,所以*tf内容就被修改了。导致判断跨天的条件(lo->tm_mday != tf->tm_mday) 恒为假。
实际应该使用函数返回指向的值,而不能使用指针,否则会指向同一地址从而使用了被修改的值。
3 结论:解决方案及效果
正确方法为,调用localtime后将指针指向的值保存到变量中:
struct tm tf;
struct tm lo;
tf = *localtime( &now );
lo = *localtime( &m_LastOpenTime );
4 经验总结:预防措施和规范建议
localtime()系统调用返回的是指向函数内部的static变量的指针,每次调用都会修改此static变量的值。如果使用指针接收返回值,则后面的调用会修改前面调用的指针指向的值。调用此函数后需要将指针指向的内容保存以供使用。
由于localtime使用了函数内部的static变量,对于多线程的环境需要使用线程安全函数localtime_r(struct tm *localtime_r(const time_t *restrict clock, struct tm *restrict res);)来代替。
5 备注
6 考核点
指针指向的变量值改变后,其他指向该变量的指针引用的值也相应变化。
7 试题
1.系统函数localtime 定义为: struct tm *localtime(const time_t *timer); 调用此函数将time_t 类型的时间转换为tm结构的当地时间,返回指针指向函数内部的静态变量。tm结构的主要成员定义如下:
int tm_sec; /* seconds after the minute - [0, 60] */
/* for leap seconds */
int tm_min; /* minutes after the hour - [0, 59] */
int tm_hour; /* hour since midnight - [0, 23] */
int tm_mday; /* day of the month - [1, 31] */
int tm_mon; /* months since January - [0, 11] */
int tm_year; /* years since 1900 */
int tm_wday; /* days since Sunday - [0, 6] */
假设变量now为当天的时间,lastDayTime为上一天的时间:
time_t now = time(NULL);
time_t lastDayTime = now - (24*60*60) ; // 上一天的时间
那么执行如下程序片断后,结果为: (B)
tm * pLastDay = localtime(&lastDayTime);
tm * pCurrentDay = localtime(&now);
if (pLastDay->tm_mday == pCurrentDay->tm_mday)
{
printf("same day of month!\n");
}
else if (pLastDay->tm_mday < pCurrentDay->tm_mday)
{
printf("last day < current day!\n");
}
else
{
printf("last day > current day!\n");
}
A 由于可能跨月,打印结果不确定。
B 打印:same day of month!
C 打印:last day < current day!
D 打印:last day > current day!
阅读(758) | 评论(0) | 转发(0) |