本文實例分析了C++編譯器無法捕捉到的8種錯誤,分享給大家供大家參考之用。有助于深入理解C++運行原理,具體分析如下:
眾所周知,C++是一種復雜的編程語言,其中充滿了各種微妙的陷阱。在C++中幾乎有數不清的方式能把事情搞砸。幸運的是,如今的編譯器已經足夠智能化了,能夠檢測出相當多的這類編程陷阱并通過編譯錯誤或編譯警告來通知程序員。最終,如果處理得當的話,任何編譯器能檢查到的錯誤都不會是什么大問題,因為它們在編譯時會被捕捉到,并在程序真正運行前得到解決。最壞的情況下,一個編譯器能夠捕獲到的錯誤只會造成程序員一些時間上的損失,因為他們會尋找解決編譯錯誤的方法并修正。
那些編譯器無法捕獲到的錯誤才是最危險的。這類錯誤不太容易察覺到,但可能會導致嚴重的后果,比如不正確的輸出、數據被破壞以及程序崩潰。隨著項目的膨脹,代碼邏輯的復雜度以及眾多的執行路徑會掩蓋住這些bug,導致這些bug只是間歇性的出現,因此使得這類bug難以跟蹤和調試。盡管本文的這份列表對于有經驗的程序員來說大部分都只是回顧,但這類bug產生的后果往往根據項目的規模和商業性質有不同程度的增強效果。
這些示例全部都在Visual Studio 2005 Express上測試過,使用的是默認告警級別。根據你選擇的編譯器,你得到的結果可能會有所不同。我強烈建議所有的程序員朋友都采用最高等級的告警級別!有一些編譯提示在默認告警級別下可能不會被標注為一個潛在的問題,而在最高等級的告警級別下就會被捕捉到!
1)變量未初始化
變量未初始化是C++編程中最為常見和易犯的錯誤之一。在C++中,為變量所分配的內存空間并不是完全“干凈的”,也不會在分配空間時自動做清零處理。其結果就是,一個未初始化的變量將包含某個值,但沒辦法準確地知道這個值是多少。此外,每次執行這個程序的時候,該變量的值可能都會發生改變。這就有可能產生間歇性發作的問題,是特別難以追蹤的??纯慈缦碌拇a片段:
if (bValue) // do Aelse // do B
如果bValue是未經初始化的變量,那么if語句的判斷結果就無法確定,兩個分支都可能會執行。在一般情況下,編譯器會對未初始化的變量給予提示。下面的代碼片段在大多數編譯器上都會引發一個警告信息。
int foo(){ int nX; return nX;}
但是,還有一些簡單的例子則不會產生警告:
void increment(int &nValue){ ++nValue;}int foo(){ int nX; increment(nX); return nX;}
以上的代碼片段可能不會產生一個警告,因為編譯器一般不會去跟蹤查看函數increment()到底有沒有對nValue賦值。
未初始化變量更常出現于類中,成員的初始化一般是通過構造函數的實現來完成的。
class Foo{private: int m_nValue;public: Foo(); int GetValue() { return m_bValue; }}; Foo::Foo(){ // Oops, 我們忘記初始化m_nValue了} int main(){ Foo cFoo; if (cFoo.GetValue() > 0) // do something else // do something else}
注意,m_nValue從未初始化過。結果就是,GetValue()返回的是一個垃圾值,if語句的兩個分支都有可能會執行。
新手程序員通常在定義多個變量時會犯下面這種錯誤:
int nValue1, nValue2 = 5;
這里的本意是nValue1和nValue2都被初始化為5,但實際上只有nValue2被初始化了,nValue1從未被初始化過。
由于未初始化的變量可能是任何值,因此會導致程序每次執行時呈現出不同的行為,由未初始化變量而引發的問題是很難找到問題根源的。某次執行時,程序可能工作正常,下一次再執行時,它可能會崩潰,而再下一次則可能產生錯誤的輸出。當你在調試器下運行程序時,定義的變量通常都被清零處理過了。這意味著你的程序在調試器下可能每次都是工作正常的,但在發布版中可能會間歇性的崩掉!如果你碰上了這種怪事,罪魁禍首常常都是未初始化的變量。
2)整數除法
C++中的大多數二元操作都要求兩個操作數是同一類型。如果操作數的不同類型,其中一個操作數會提升到和另一個操作數相匹配的類型。在C++中,除法操作符可以被看做是2個不同的操作:其中一個操作于整數之上,另一個是操作于浮點數之上。如果操作數是浮點數類型,除法操作將返回一個浮點數的值:
float fX = 7;float fY = 2;float fValue = fX / fY; // fValue = 3.5
如果操作數是整數類型,除法操作將丟棄任何小數部分,并只返回整數部分。
int nX = 7;int nY = 2;int nValue = nX / nY; // nValue = 3
如果一個操作數是整型,另一個操作數是浮點型,則整型會提升為浮點型:
float fX = 7.0;int nY = 2;float fValue = fX / nY; // nY 提升為浮點型,除法操作將返回浮點型值// fValue = 3.5
有很多新手程序員會嘗試寫下如下的代碼:
int nX = 7;int nY = 2;float fValue = nX / nY; // fValue = 3(不是3.5哦!)
這里的本意是nX/nY將產生一個浮點型的除法操作,因為結果是賦給一個浮點型變量的。但實際上并非如此。nX/nY首先被計算,結果是一個整型值,然后才會提升為浮點型并賦值給fValue。但在賦值之前,小數部分就已經丟棄了。
要強制兩個整數采用浮點型除法,其中一個操作數需要類型轉換為浮點數:
int nX = 7;int nY = 2;float fValue = static_cast<float>(nX) / nY; // fValue = 3.5
因為nX顯式的轉換為float型,nY將隱式地提升為float型,因此除法操作符將執行浮點型除法,得到的結果就是3.5。
通常一眼看去很難說一個除法操作符究竟是執行整數除法還是浮點型除法:
z = x / y; // 這是整數除法還是浮點型除法?
但采用匈牙利命名法可以幫助我們消除這種疑惑,并阻止錯誤的發生:
int nZ = nX / nY; // 整數除法double dZ = dX / dY; // 浮點型除法
有關整數除法的另一個有趣的事情是,當一個操作數是負數時C++標準并未規定如何截斷結果。造成的結果就是,編譯器可以自由地選擇向上截斷或者向下截斷!比如,-5/2可以既可以計算為-3也可以計算為-2,這和編譯器是向下取整還是向0取整有關。大多數現代的編譯器是向0取整的。
3)= vs ==
這是個老問題,但很有價值。許多C++新手會弄混賦值操作符(=)和相等操作符(==)的意義。但即使是知道這兩種操作符差別的程序員也會犯下鍵盤敲擊錯誤,這可能會導致結果是非預期的。
// 如果nValue是0,返回1,否則返回nValueint foo(int nValue){ if (nValue = 0) // 這是個鍵盤敲擊錯誤 ! return 1; else return nValue;} int main(){ std::cout << foo(0) << std::endl; std::cout << foo(1) << std::endl; std::cout << foo(2) << std::endl; return 0;}
函數foo()的本意是如果nValue是0,就返回1,否則就返回nValue的值。但由于無意中使用賦值操作符代替了相等操作符,程序將產生非預期性的結果:
000
當foo()中的if語句執行時,nValue被賦值為0。if (nValue = 0)實際上就成了if (nValue)。結果就是if條件為假,導致執行else下的代碼,返回nValue的值,而這個值剛好就是賦值給nValue的0!因此這個函數將永遠返回0。
在編譯器中將告警級別設置為最高,當發現條件語句中使用了賦值操作符時會給出一個警告信息,或者在條件判斷之外,應該使用賦值操作符的地方誤用成了相等性測試,此時會提示該語句沒有做任何事情。只要你使用了較高的告警級別,這個問題本質上都是可修復的。也有一些程序員喜歡采用一種技巧來避免=和==的混淆。即,在條件判斷中將常量寫在左邊,此時如果誤把==寫成=的話,將引發一個編譯錯誤,因為常量不能被賦值。
4)混用有符號和無符號數
如同我們在整數除法那一節中提到的,C++中大多數的二元操作符需要兩端的操作數是同一種類型。如果操作數是不同的類型,其中一個操作數將提升自己的類型以匹配另一個操作數。當混用有符號和無符號數時這會導致出現一些非預期性的結果!考慮如下的例子:
cout << 10 亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb 亚洲成色777777在线观看影院| 国产91色在线免费| 亚洲片在线观看| 在线观看国产成人av片| 日本亚洲欧洲色| 亚洲日本中文字幕免费在线不卡| 国产精品自产拍在线观| 日本成人激情视频| 亚洲自拍在线观看| 国产在线精品播放| 亚洲国产成人在线播放| 国产精品九九久久久久久久| 尤物yw午夜国产精品视频| 欧美精品免费在线观看| 国产精品久久久久久av福利| 国产情人节一区| 日韩av不卡电影| 精品久久香蕉国产线看观看亚洲| 欧美成人在线网站| 亚洲色图欧美制服丝袜另类第一页| 51精品国产黑色丝袜高跟鞋| 成人黄色短视频在线观看| 日韩小视频在线观看| 久久久亚洲精品视频| 久久久人成影片一区二区三区观看| 18性欧美xxxⅹ性满足| 日韩在线一区二区三区免费视频| 久久免费精品日本久久中文字幕| 久久精品最新地址| 亚洲精品98久久久久久中文字幕| 午夜精品在线视频| 久久国产精品影视| 欧美在线一区二区三区四| 91老司机在线| 成人久久久久久久| 亚洲综合中文字幕在线观看| 午夜精品久久久久久久久久久久久| 日韩av在线导航| 原创国产精品91| 久久久久久久久久av| 免费99精品国产自在在线| 国产视频久久久久久久| 欧美精品一区三区| 亚洲精品网址在线观看| 亚洲影视中文字幕| 91成人在线播放| 国产伊人精品在线| 中文字幕亚洲无线码a| 亚洲精品日产aⅴ| 中文字幕国内精品| 久久九九有精品国产23| 久久精品视频在线观看| 日韩在线视频免费观看高清中文| 国产亚洲激情在线| 国产午夜精品一区二区三区| 九九热99久久久国产盗摄| 成人动漫网站在线观看| 国产一区红桃视频| 国产婷婷97碰碰久久人人蜜臀| 国产精品吊钟奶在线| 欧美专区福利在线| 精品久久久视频| 最近中文字幕mv在线一区二区三区四区| 亚洲精品网站在线播放gif| 一区二区三区高清国产| 亚洲欧美日韩精品久久| 国产亚洲欧美视频| 日韩成人免费视频| 最新国产精品拍自在线播放| 国产精品美女久久久久av超清| 欧美高清一级大片| 国产原创欧美精品| 成人福利视频网| 久久精品99久久香蕉国产色戒| 亚洲深夜福利网站| 免费不卡欧美自拍视频| 午夜精品久久久久久99热软件| 91国产一区在线| 欧美在线视频网站| 成人欧美在线视频| 一本一本久久a久久精品综合小说| 91免费看视频.| 欧美精品亚州精品| 亚洲自拍小视频| 亚洲国产欧美一区二区三区久久| 亚洲国产成人久久综合一区| 亚洲欧美日本另类| 欧美网站在线观看| 亚洲第一二三四五区| 欧美激情va永久在线播放| 久久久亚洲精选| 亚洲精品xxxx| 国产精品久久久久福利| 亚洲天堂视频在线观看| 精品视频一区在线视频| 中文字幕亚洲综合久久| 福利二区91精品bt7086| 亚洲人午夜精品| 中文字幕精品视频| 欧美激情一区二区三区成人| 欧美午夜美女看片| 亚洲最大激情中文字幕| 国产午夜精品视频| 精品久久久精品| 91精品国产综合久久香蕉最新版| 中文国产成人精品久久一| 久热精品视频在线| 亚洲成人xxx| 亚洲精品久久久久中文字幕欢迎你| 蜜臀久久99精品久久久无需会员| 亚洲精品成人久久| 久久久精品一区二区| 久久久久久久影院| 国产免费一区视频观看免费| 国产精品久久久久久久av大片| 91a在线视频| 国产成人精品在线观看| 欧美性高跟鞋xxxxhd| 精品一区二区亚洲| 在线视频欧美日韩精品| 久久精品91久久香蕉加勒比| 国产一区视频在线| 亚洲精品视频在线观看视频| 狠狠躁夜夜躁人人爽天天天天97| 精品视频偷偷看在线观看| 91精品久久久久久久久久| 久久久精品国产一区二区| 91久久精品日日躁夜夜躁国产| 一个色综合导航| 欧美日韩中文字幕在线视频| 国产成人在线亚洲欧美| 国产精品成人一区二区三区吃奶| 91成人福利在线| 亚洲国产精品va在线观看黑人| 亚洲精品mp4| 蜜臀久久99精品久久久无需会员| 欧美成人剧情片在线观看| 91影院在线免费观看视频| 亚洲午夜色婷婷在线| 国产精品久久中文| 久热精品在线视频| 亚洲人成网站免费播放| 亚洲男人av在线| 国产精品久久在线观看| 欧美激情乱人伦| 日韩av在线一区| 欧美精品情趣视频| 亚洲永久在线观看| 亚洲国产天堂网精品网站| 欧美一乱一性一交一视频| 日韩中文字幕第一页| 国产精品久久综合av爱欲tv| 国产噜噜噜噜噜久久久久久久久| 国产精品美女在线| 国产精品99久久久久久白浆小说| 九九热这里只有精品6| 国产精品一二三在线| 欧美色道久久88综合亚洲精品| 在线视频精品一| 亚洲欧美日韩视频一区| 日本三级韩国三级久久| 日韩在线视频观看正片免费网站| 人妖精品videosex性欧美| 国产成人小视频在线观看|