越是簡單的越不能忽視
類型強轉一定要 注意! 注意! 注意!
以上兩天結論前前後後花了我三天工作時間才讓我意識到並學到。
有的時候,不管你小心還是無意,坑就在那裏,踩的人夠多,也許就填平了。
在工作中,分配到一個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))
原因
爲什麼會出現這樣的情況呢,因爲 a 是一個float型的數據,我們看它是2.3,但是它在內存裏就不一定是2.3,它可以是2.29999999999999999,或者2.30000000000000001,因爲浮點型的範圍爲-2^128 ~ +2^128,也即-3.40E+38 ~ +3.40E+38;