2014-09-06 56 views
2

如果我有這樣的功能:功能不使用回C++

int addNumbers(int x, int y) 
{ 
    return x + y; 
} 

,如果我用它作爲這樣的:

cout << addNumbers(4, 5) << endl; 

它會返回並打印9。使用上面相同的cout行,如果我註釋掉或刪除addNumbers中的返回,它將返回並打印1。如果我這樣做:

int addNumbers(int x, int y) 
{ 
    int answer = x + y; 
    //return x + y; 
} 

它將使用收益自動返回和打印9,沒有我。同樣,我可以寫int answer = x;它將返回4。我也可以這樣寫:

int addNumbers(int x, int y) 
{ 
    int answer = x; 
    answer = 1; 
    //return x + y; 
} 

,它仍然會返回4.

究竟是返回,爲什麼?當我使用參數變量時,它只返回1以外的值,但它不返回如上例所示的變量答案,因爲我將其更改爲1,並且它仍然返回值x (4)

+1

這是UB,它返回,因爲它發生在堆棧上,爲x64構建,它將是一個「隨機」值 – paulm 2014-09-06 08:43:31

+1

它是[* undefined behavior *](http://en.wikipedia.org /維基/ Undefined_behavior)。 – 2014-09-06 08:46:04

回答

2

§6.6.3[stmt.return]/P2:

流動關閉的功能的端部是相當於沒有 值的return;這會導致在返回值 函數中出現未定義的行爲。

main()是一個特殊的例外。流走的main()末相當於return 0;

允許UB包括:

  • 回到你「想要」返回
  • 返回垃圾值,而不是
  • 崩潰
  • 發送您的密碼給黑客
  • 格式化您的硬盤驅動器
  • Mak荷蘭國際集團在您的計算機爆炸和打擊你的腿斷
  • 咒術鼻惡魔
  • 在時間旅行回來,你的程序固定在正確的事情
  • 創建黑洞
  • ......

但嚴重的是,UB可以以各種方式表現出來。例如,給定這樣的代碼:

#include <iostream> 
bool foo = false; 
int addNumbers(int x, int y) 
{ 
    int answer = x; 
    answer = 1; 
    //return x + y; 
} 

int main(){ 
    if(!foo) { 
    addNumbers(10, 20); 
    std::cout << 1 << std::endl; 
    } 
    else { 
    std::cout << 2 << std::endl; 
    } 
} 

鐺++在-02 prints2

爲什麼?因爲它推斷addNumbers(10, 20);具有未定義的行爲,這允許它假定第一個分支從未被採用並且foo始終爲true,儘管這顯然不是這種情況。

+0

因此,即使在這一個(非常基本的)場景中,它總是會返回我「預計」它返回的結果,但在其他機器或更復雜的場景中肯定無法保證? – Sam 2014-09-06 08:54:00

+0

@Sam它不保證任何事情。 * UB可能會發生任何事情。 – 2014-09-06 08:56:27

+0

感謝您的回答,您添加的示例真的有所幫助。奇怪的東西,真的很有趣。 – Sam 2014-09-06 09:21:31

0

您正在觀察未定義的行爲。 「爲什麼」該程序沒有很好的理由,因爲它不是一個格式良好的程序。它可以做任何事情,包括運行時從磁盤刪除自己。啓用編譯器警告和錯誤(例如g++ -Wall -Wextra -Werror),您將被自動禁止編寫此類代碼(如您應該那樣)。

1

您正在依賴「未定義的行爲」。對於簡單類型,返回值通常存儲在寄存器中,也可用於計算結果的形成。但它也可能不被使用,並且你得到一些任意的「隨機」結果,並且是「未定義的行爲」,你也可能得到你的計算機可能執行的任何其他可能的操作 - 例如崩潰或執行一些你沒有執行的代碼要執行...

0

因此,它是未定義的行爲,反彙編你的二進制可能解釋爲什麼這樣的值返回。

objdump -d example.bin

由於返回值與RAX註冊表關聯,如果編譯器使用RAX處理函數,返回的值是留在兵營的價值。

無論如何,你不應該這樣做,因爲當你編寫這樣的代碼時,編譯器優化和註冊表的使用是未知的。