越是简单的越不能忽视
类型强转一定要 注意! 注意! 注意!
以上两天结论前前后后花了我三天工作时间才让我意识到并学到。
有的时候,不管你小心还是无意,坑就在那里,踩的人够多,也许就填平了。
在工作中,分配到一个bug,简单描述一下:该程序很庞大,由QT编写,跨平台,支持ubuntu和windows,其中一个模块需要控制海康摄像头,代码中有海康的SDK。bug的现象是无法设定到指定的摄像头调焦倍数与焦距,表现就是摄像头模糊不清,无法正常拍摄,且只在windows下发生。
本文由以下部分组成:
- 调试步骤
- SDK验证
- 2.3 * 10 = 22
调试步骤
工程代码缺陷
bug刚刚拿到手,看了遍代码,一个显而易见的缺陷暴露出来:
- 开环式代码
什么是开环式代码?
简单来看,这部分代码就是这样的:
缺陷有3:
- 没判断设定值是否合法
- 没检查设置是否成功
- 没有防御机制,没有给出设置失败的处理办法
于是添加:
- 合法性检查
- 开定时循环检查
- 定时器中检查不成功重设
疑似SDK缺陷
同样的代码,在不同的系统中表现不同。
ubuntu 14.04 : 正常
windows7 : 异常
采用排除法,代码中逻辑处理都是一致的,唯一不同的就是海康的sdk,一个是linux64版本,一个是win32版本。
运行时一个加载.so库,一个加载dll。
那么就来找找SDK的茬吧
SDK验证
此处略,详见:
2.3 * 10 = 22
查来查去,最终比对自己的验证sdk的demo与工程代码,发现最可疑的就是, 聚焦倍数(zoom值)的处理是有差异,验证demo中直接使用float
,而工程代码中会强制转换int
,便于显示以及处理,可我恰恰没想到,就这个强制转是问题所在,确切的说,是不同系统下的处理是问题原因所在。
先列出罪魁祸首:
zoom = rOpticalZoomLevelP * 10;
再来看一下其中变量的声明与定义:
int zoom;
float rOpticalZoomLevelP = 0.0f;
使用qDebug()
打印发现:
rOpticalZoomLevelP*10
之前rOpticalZoomLevelP
值是2.3
而在之后强转赋值给zoom
后,zoom
是22。
也就是说:
2.3 * 10 = 22
???
ubuntu下
系统:ubuntu16.04
gcc版本:gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.10)
demo:
int main(int argc, char **argv)
{
float a = 2.3f;
int b =0;
b = a*10;
printf("b ------>%d\n",b);
return 0;
}
result:
windows7下
系统:windows7
gcc版本:MinGW 4.9.1 32bit MinGW
demo:
int main(int argc, char **argv)
{
float a = 2.3f;
int b =0;
b = a*10;
printf("b ------>%d\n",b);
return 0;
}
result:
b -------> 22
问题原因还是未知,但是可以规避,使用qRound()
函数:
zoom = qRound(qreal(rOpticalZoomLevelP*10))