问题1
问题描述
在搭建EMG信号处理系统时,我需要读取一个txt文件。在debug时能正常读取。在release版本下却不能获取其中的信息。后来发现问题在于我使用了assert语句。我的读取代码如下:
void Config::gen_data_list()
{
QFile f(select_dataset_path);
assert(f.open(QIODevice::ReadOnly | QIODevice::Text));
while (!f.atEnd())
{
QString l = f.readLine();
qDebug() << l << endl;
if (l.compare('\n') == 0)
continue;
else
data_list.append(l.simplified());
}
data_num = data_list.length();
trial_num = data_num * blk_num;
}
解决办法
在release条件下,data_num始终是0。因为assert语句被忽略掉了,所以txt文件一直都没有被读取。将代码改成如下形式,release版本下也能正常读取了。
void Config::gen_data_list()
{
QFile f(select_dataset_path);
bool isOpen = f.open(QIODevice::ReadOnly | QIODevice::Text);
assert(isOpen);
while (!f.atEnd())
{
QString l = f.readLine();
qDebug() << l << endl;
if (l.compare('\n') == 0)
continue;
else
data_list.append(l.simplified());
}
data_num = data_list.length();
trial_num = data_num * blk_num;
}
这样isOpen的值取决于文件是否打开。所以f.open(QIODevice::ReadOnly | QIODevice::Text)这部分的内容一定会被执行的。
在VS中,也可以在属性中打开编译调试代码开关,这样就会编译assert函数了。
原因探究
查阅相关资料后,我发现assert语句在windows下,利用VC的编译器时,会被忽略掉而不执行。这取决于release和debug时的编译器优化方式。在linux条件下,使用gcc编译时则不会忽略assert语句。其他深入的编译原理相关的原因就不再接着探究了。
总的来说,不管使用何种编译器,代码规范化是很重要的。assert语句不应该被用来检测文件读取,以及输入是否合法等问题。也不能把赋值操作等语句放在其中。总之,检查代码的时候,把assert语句去掉,如果代码的正常逻辑没有问题。那么代码就是正常的。assert应该是用来检测参数的合法性以及参数值的大小等涉及代码完备性和安全性的问题。
问题2
问题描述
在搭建EMG信号处理系统时,需要通过state参数来判断是否暂停函数中的for循环。在debug条件下,暂停和恢复都能正常运行。暂停条件下停止实验也能正常运行,但是在release条件下,暂停后就没法恢复正常运行了,而且暂停后要么会在下一个trial时停止,要么在后面恢复时,没有响应。代码块如下:
for (int i = 1; i <= exp_c.blk_num; i++){
for (int j = 1; j <= exp_c.data_num; j++){
if (th_record_state == 2){
while (true){
if (main_th_stop){
stop_experiment();
break;
}
if (th_record_state == 1)
break;
}
}
for (int k = 1; k <= state_num; k++){
Process();
}
需要实现的功能是,在th_record_state为1(record state)时,实验正常进行;在th_record_state为2(pause state)时,实验暂停;在th_record_state为0时,main_th_stop为true,实验结束。
解决办法
由于release版本下,VS的优化器认为while循环中的内容对外部代码没有影响,且while循环会占用很多计算量。所以在release版本下,while循环中的代码会被忽略掉。所以在while循环中加入延时,减少因为暂停导致的循环次数。这样优化器会重新加入while循环的内容。(这部分涉及到VS中的编译优化的问题,没有深究原因)。修改后的代码如下:
for (int i = 1; i <= exp_c.blk_num; i++){
for (int j = 1; j <= exp_c.data_num; j++){
if (th_record_state == 2){
while (true){
Sleep(100);
if (main_th_stop){
stop_experiment();
break;
}
if (th_record_state == 1)
break;
}
}
for (int k = 1; k <= state_num; k++){
Process();
}
尽管这样会损失一些反应时间,但是实验系统对反应时间的要求也不高,而且Sleep函数的时间可以根据实验所需的反应时间修改。这种解决方案也可以接受。
原因探究
主要的原因还是debug和release版本下,VS的优化方法不一样。优化的参数可以在项目属性中调整。但是release版本的代码对稳定性的要求会更高,类似于数组越界,指针赋值等问题,在debug时可能没问题。但是release时就会出现问题。此时一定要检查代码的规范性问题,以及代码中的一些合理性问题,例如本文中出现的assert语句中加入文件读取语句,while循环不加延时导致大量无效循环等问题。