天天看點

《編寫高品質代碼:改善c程式代碼的125個建議》——建議2-5:小心使用無符号類型帶來的陷阱

本節書摘來自華章計算機《編寫高品質代碼:改善c程式代碼的125個建議》一書中的第1章,建議2-5,作者:馬 偉 更多章節内容可以通路雲栖社群“華章計算機”公衆号檢視。

有過面試經曆的同學可能曾碰到如代碼清單1-6所示的問題。

對代碼清單1-6進行初步分析可以得出,sizeof(array)的傳回結果為24,而i的值為-1,是以執行語句“if ( i <= sizeof(array))”所傳回的結果應該為true,即輸出結果為“i <= sizeof(array)”。但實際情況并非如此,其輸出結果如圖1-6所示。

《編寫高品質代碼:改善c程式代碼的125個建議》——建議2-5:小心使用無符号類型帶來的陷阱

那麼,究竟是什麼原因導緻出現這樣的輸出結果呢?

其實,要回答這個問題并不難。我們知道sizeof()的傳回結果是size_t類型,而size_t類型是一種無符号整數類型。當有符号整數類型和無符号整數類型進行運算時,有符号整數類型會先自動轉化成無符号整數類型(請特别注意這一點)。

是以,在代碼清單1-6中,當 i 與sizeof(array)進行比較時,即執行語句“if ( i <= sizeof(array))”,i會自動更新為無符号整數類型。又因為i的值為-1,在它轉換為無符号整數類型後就變成一個非常大的正整數(如-1在32位機器上存儲為0xffffffff,而它被解釋為無符号整數時就是232-1,即4294967295),遠遠大于sizeof(array)的傳回結果24。

為了加深讀者的了解,我們再來看代碼清單1-7所示的這個例子。

在代碼清單1-7中,當執行語句“a-b”時,變量a會自動由int類型轉換為unsigned int類型,再與變量b執行減法運算(即“a-b”),“a-b”的運算結果為0xffffffff。當程式使用“%d”(有符号十進制整數)格式輸出時,0xffffffff被轉換為-1;當程式使用“%u”(無符号十進制整數)格式輸出時,0xffffffff被轉換為4294967295;最後,程式執行“0xffffffff >>1”運算時,其運算結果為0x7fffffff。當程式使用“%d”(有符号十進制整數)格式輸出時,0x7fffffff被轉換為2147483647。代碼清單1-7的輸出結果如圖1-7所示。

《編寫高品質代碼:改善c程式代碼的125個建議》——建議2-5:小心使用無符号類型帶來的陷阱

https://yqfile.alicdn.com/e372ae0615b323a6331a3f91591d052299565055.png" >

由上面兩個例子可以看出,将有符号類型與無符号類型混合使用是很危險的。是以,我們一定要小心這個資料轉換陷阱,盡量少在代碼中使用無符号類型,以免增加不必要的複雜性。尤其是不要僅僅因為無符号數不存在負值而用它來表示某些數量(如年齡、人口等無負數的值)。建議盡量使用像int這樣的類型,這樣在設計更新混合類型的複雜細節時,就不必擔心邊界情況了(比如不用擔心-1被翻譯為非常大的正整數)。如果必須使用無符号類型,則應該在表達式中使用強制類型轉換,使操作數均為有符号類型或者無符号類型,這樣就不必由編譯器來選擇結果的類型,進而避免存在潛在錯誤的可能性。比如,我們可以通過強制轉換将代碼清單1-6 改寫為代碼清單1-8。

在代碼清單1-8中,我們将語句“ if ( i <= sizeof(array))”改成“if ( i <= (int)sizeof(array))”,也就是通過強制類型将其轉換成int類型,因而程式的輸出結果為i <= sizeof(array)。

繼續閱讀