轉載:bool型返回值函數,沒寫return語句的時候返回啥?
因為漏寫了一個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<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"> </span>
從 上面的分析中我們可以看到,但程序沒有寫返回語句時,我們去那返回值時,這個值就是原來返回值寄存器(eax)里面已經存在的值,這是不確定的。比如我們 這里返回了一個不為0,1的數字時,接下來我們進行bool判斷時,無論與1異或,還是與0異或,都不會使改寄存器變0,因而對應的test語句也就總是 成立了。
我們使用指針去修改bool變量的值也能達到上面的同樣的效果。而我們直接用數字去比較的時候卻沒有這個效果,是因為程序在比較之前會做一次隱性的類型轉換。
附 exa, ax, ah, al 寄存器的介紹:
先請看圖,圖看懂了就基本解決這個了疑問了。
雖說EAX是32位的寄器,但其實只是在原有的8086CPU的寄存器AX上增加了一倍的數據位數而已。故而EAX與AX根本不可能獨立,二者是整體與部分的關系。
對EAX直接賦值,若更改了低16位自然會改變了AX值,而AX又可以影響EAX整體。而AH,AL寄存器和AX之間的關系也是如此。
=========================================================================
帶返回值與不帶返回值函數的匯編對比: