令人崩溃的“ 2.3 * 10 = 22 ”

版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/qq_30650153/article/details/82699863

越是简单的越不能忽视
类型强转一定要 注意! 注意! 注意!

以上两天结论前前后后花了我三天工作时间才让我意识到并学到。
有的时候,不管你小心还是无意,坑就在那里,踩的人够多,也许就填平了。
在工作中,分配到一个bug,简单描述一下:该程序很庞大,由QT编写,跨平台,支持ubuntu和windows,其中一个模块需要控制海康摄像头,代码中有海康的SDK。bug的现象是无法设定到指定的摄像头调焦倍数与焦距,表现就是摄像头模糊不清,无法正常拍摄,且只在windows下发生。
本文由以下部分组成:

  • 调试步骤
  • SDK验证
  • 2.3 * 10 = 22

调试步骤

工程代码缺陷

bug刚刚拿到手,看了遍代码,一个显而易见的缺陷暴露出来:

  • 开环式代码

什么是开环式代码?
简单来看,这部分代码就是这样的:

Created with Raphaël 2.1.2 开始 输入倍数焦距 设置倍数焦距 结束

缺陷有3:

  1. 没判断设定值是否合法
  2. 没检查设置是否成功
  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))

猜你喜欢

转载自blog.csdn.net/qq_30650153/article/details/82699863
2.3