2013-08-03 40 views
5

考慮下面的代碼片段:C++編程謎語,樂趣函數指針

#include <string> 
#include <iostream> 

int main() 
{ 
    std::string prefix("->"), middle(), suffix("<-"); 
    std::cout << "Test: " << prefix << middle << suffix << std::endl; 

    return 0; 
} 

先進的C++程序員會立即看到middle()並沒有叫std::string的默認構造函數,取而代之的則是一個函數聲明。

雖然有趣:爲什麼GCC產生下面的輸出:

Test: ->1<- 

相反,Visual Studio的鏈接錯誤?有人知道這裏發生了什麼嗎?

+0

我有一個downvote和這個問題(離題)關閉請求,任何人都可以告訴我爲什麼。這樣的問題真的是關於SO的話題嗎? –

回答

7

cout一起使用時,函數指針將轉換爲bool

爲什麼函數指針不會隱式轉換爲void *,這是運算符<上的重載?因爲函數指針不是對象指針。

C++ 11§4.10/ 2:

類型的prvalue「指向cv T,」,其中T是一個對象類型,可以被轉化成類型的指針」,以CV空隙的prvalue 」。將「指向cv T的指針」轉換爲「指向cv void的指針」的結果指向類型T的對象所在的存儲位置的開始,就好像該對象是類型T的最派生對象(1.8) (也就是說,不是基類子對象)。空指針值被轉換爲目標類型的空指針值。

+2

謝謝,我正在猜測這樣的事情。你知道VS爲什麼會產生鏈接錯誤嗎?哪一種行爲是「標準的」,哪一種是「錯誤的」? –

+4

@ D.R .:我認爲你的程序有未定義的行爲,所以兩者都是「正確的」。規則如下:「每個程序都應該包含每個非內聯函數或該程序中odr使用的變量的一個定義; **不需要診斷**。」 –

+0

這個怎麼樣? http://stackoverflow.com/questions/2064692/how-to-print-function-pointers-with-cout –

1

正如Yu所說,函數指針正在轉換爲bool

g ++優化器顯然是預先評估轉換,而Visual C++實際上生成代碼來測試函數地址是否爲空,這需要鏈接器提供函數地址。

規則是

每個程序應包含在該程序中所ODR使用的每個非內聯函數或變量的正好一個定義;不需要診斷。

功能是因爲你使用它的地址 ODR使用。通過不提供定義,您違反了這一規則,並且標準不需要診斷,這意味着工具鏈可以自由地做任何事情。

Visual C++正在生成一個診斷,儘管它不是必需的。

g ++給出了轉換爲bool的實際結果,因爲它知道實際函數對函數指針的衰減永遠不會產生空函數指針。

但格式化您的硬盤驅動器將同樣有效,因爲標準沒有說明工具鏈可以或不能在這裏做什麼。