bool型返回值函數,沒寫return語句的時候返回啥?

轉載網址:http://hi.baidu.com/pope123/blog/item/7c9315f7630b6630730eec79.html

今天因爲漏寫了一個return語句,g++又沒開warning,結果就悲劇了,調用的時候出現了奇怪的現象,於是就測試了一把到底沒寫return的時候返回什麼東西。

例程:

#include <iostream>
#include <vector>
using namespace std;
bool func()
{
    int i=10;
    i++;
}
int main()
{
bool a = func();
bool b=true;
bool c=100;
cout<<!(a)<<endl;
cout<<!(b)<<endl;
cout<<!(c)<<endl;
cout<<(a)<<endl;
cout<<(b)<<endl;
cout<<(c)<<endl;
cout<<!10<<endl;
cout<<func()<<endl;
if(func()==true)
    cout<<"true"<<endl;
if(func()==false)
    cout<<"false"<<endl;
if(!func()==true)
    cout<<"true"<<endl;
if(!func()==false)
    cout<<"false"<<endl;

}

程序輸出:

5
0
0
4
1
1
0
64
true
false
true
false

多次運行時上面的除0,1外的數字是隨機的。

而且從if語句的判斷當中我們可以看到當我們那這個沒有返回語句的函數直接來判斷時,他已經沒有了bool變量的特性了。

再跟true,false的比較中他們都是成立的。這個時候但我們不小心使用了if else結構的時候,就永遠只會執行if而不會到else的語句中了。

所以當bool返回值的函數,在沒寫返回語句的時候,他並不會默認地返回一個true和false,而是一個無定義的行爲,會導致後面的判斷出錯。

 

那到底是怎麼出現這樣不合邏輯的現象的呢,讓我們繼續實驗來一窺其中的奧祕。

要想知道其中的過程,我們首先用g++ -S來編譯這份代碼的彙編代碼來看看。

整體彙編代碼過長就不全部貼上來了,我們只來關注我們的if語句(第一個if語句和第二個)的彙編。

.L7:                                //第一個if語句
call    _Z4funcv              //首先調用func函數
xorl    $1, %eax             //將返回結果%eax與1作異或操作
testb   %al, %al             //判斷al寄存器是否爲0,這裏的test操作就是作一次and,並設置標誌位ZF;關於al 與eax的關係見下面說明。
je  .L8                            //根據標誌位ZF作跳轉。
movl    $.LC0, 4(%esp)
movl    $_ZSt4cout, (%esp)
call    _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
movl    $_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, 4(%esp)
movl    %eax, (%esp)
call    _ZNSolsEPFRSoS_E

.L8:                                  //第二個if語句,基本和1一樣,但是由於和0作異或,因爲作不作都一樣,因而沒有對應語句。
call    _Z4funcv
testb   %al, %al
je  .L9
movl    $.LC0, 4(%esp)
movl    $_ZSt4cout, (%esp)
call    _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
movl    $_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, 4(%esp)
movl    %eax, (%esp)
call    _ZNSolsEPFRSoS_E

 

從 上面的分析中我們可以看到,但程序沒有寫返回語句時,我們去那返回值時,這個值就是原來返回值寄存器(eax)裏面已經存在的值,這是不確定的。比如我們 這裏返回了一個不爲0,1的數字時,接下來我們進行bool判斷時,無論與1異或,還是與0異或,都不會使改寄存器變0,因而對應的test語句也就總是 成立了。

我們使用指針去修改bool變量的值也能達到上面的同樣的效果。而我們直接用數字去比較的時候卻沒有這個效果,是因爲程序在比較之前會做一次隱性的類型轉換。

 

附 exa, ax, ah, al 寄存器的介紹:

先請看圖,圖看懂了就基本解決這個了疑問了。

00000000 00000000 00000000 00000000
|===============EAX===============|--32個0,4個字節,2個字,1個雙字
                                    |======AX=======|--16個0,2個字節,1個字
                                    |==AH===|-----------8個0,1個字節
                                                    |===AL==|---8個0,1個字節


雖說EAX是32位的寄器,但其實只是在原有的8086CPU的寄存器AX上增加了一倍的數據位數而已。故而EAX與AX根本不可能獨立,二者是整體與部分的關係。

對EAX直接賦值,若更改了低16位自然會改變了AX值,而AX又可以影響EAX整體。而AH,AL寄存器和AX之間的關係也是如此。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章