最近在做一个黑匣子的回放系统,运行时发现第一次回放正常,再次回放时就会出现问题。开始以为是内存泄露,今天上午调试发现原来是一个静态变量在作祟。。。
首先,看下static声明的静态变量所具有的属性:内存分配位于静态存储区,只会在进程退出时才释放;当一个局部变量声明为static变量时,在函数多次进入时,变量值只被初始化一次。
然后,来看看我的问题,有一个Button,第一次点击时启动线程,开始回放。在线程函数中,循环调用了另一个函数A,来读取回放文件。由于回放文件每隔500组数据会有一个时间戳,因此在函数A中定义了一个static的变量,用于计数,每调用一次函数A,计数一次,计满500时清零,跳过时间戳。
本意是希望在多次进入函数A读取数据时,cnt记录读取的次数是否超过500组,从而决定是否跳过时间戳。因此,第一次回放时,肯定不会有任何问题。但是当停止后,再次回放时,由于cnt为静态变量,此时函数A中的cnt并没有得到初始化,仍然保留上一次的计数值,可能不为0,那么就会导致错误计数,跳过了不是时间戳的数据,因而导致了回放错误。
总结经验,我觉得在函数嵌套调用时,一定要注意子函数的static变量问题,防止出现未初始化的现象。在这里,我将cnt换成了类的成员变量来解决。
另外在回放/停止的切换中,我也用了一个static变量,顺便也提下。如下
static BOOL bResult = TRUE;
if(bResult)
{ //回放
//add code...
}
else
{ //停止
//add code...
}
bResult = !bResult; //取反
最后,我做了个测试程序,用于测试上面所述的内容。点击Button,开始打印数据;再次点击时停止;然后再次启动打印。。。m_cnt每次都从0开始打印,而cnt每次都从上一次数据开始打印。
void CtestDlg::OnBnClickedTest()
{
static BOOL bResult = TRUE;
if(bResult)
{
m_cnt = 0; //在这里每次初始化m_cnt
SetTimer(1, 1000, NULL);
}
else
KillTimer(1);
bResult = !bResult; //取反
}
void CtestDlg::OnTimer(UINT_PTR nIDEvent)
{
static int cnt = 0;
CString str;
UpdateData(TRUE);
str.Format(_T("cnt = %d, m_cnt = %d ;\r\n"), cnt++, m_cnt++);
m_strDisp+=str;
UpdateData(FALSE);
CDialog::OnTimer(nIDEvent);
}