2014-02-22 39 views
6

在C中,有的qsort()兩個版本標準庫提供:重載分辨率和 「C++」 版本的qsort的()/ bsearch(

extern "C" void qsort(void* base, size_t nmemb, size_t size, int (*compar)(const void*, const void*)); 
extern "C++" void qsort(void* base, size_t nmemb, size_t size, int (*compar)(const void*, const void*)); 

bsearch()是大約相同的。

我的問題是,當調用qsort()時,重載分辨率如何工作?它是否會根據作爲最後一個參數傳遞的函數指針的鏈接類型(「C」或「C++」)自動鏈接到相應的函數?或者調用者需要用某種額外的語法顯式指定?

(我們剛剛放好的誘惑打電話std::sort爲第二...)

+0

我從來沒有看到extern「C++」,extern「C」請求C++編譯器使用C mangling。你在哪裏看到extern「C++」void qsort .... – mpromonet

+1

@mpromonet:C++標準。 – goodbyeera

+0

我不明白你的問題,但是也許在你的可執行文件(或庫)上運行nm會回答你的問題? – mpromonet

回答

3

int (*compar)(const void*, const void*)參數有不同類型的兩個不同的重載。對於第一次過載,這是一個extern "C"函數指針參數。對於第二次過載,這是一個extern "C++"函數指針參數。你傳遞給qsort的任何函數指針都已經有了某種聯繫,這就是用來確定調用哪個超載的方法。

引述標準:

7.5聯動規格[dcl.link]

所有功能類型,具有外部鏈接函數名,以及與外部連接的變量名具有語言聯動。 [...]所有函數類型,函數名稱和變量名稱的默認語言鏈接是C++語言鏈接。具有不同語言鏈接的兩種功能類型是不同的類型,即使它們在其他方面是相同的。

事實上,我並不認爲這個標準實際上意味着要求兩個qsort重載確實有不同的聯繫。與C不同,用戶提供的標準庫函數聲明是不允許的;它們之間的相關差異是compar的類型。他們可能已被宣佈爲

extern "C" typedef int (*__compar_fnp_c)(const void *, const void *); 
extern "C++" typedef int (*__compar_fnp_cxx)(const void *, const void *); 
void qsort(void* base, size_t nmemb, size_t size, __compar_fnp_c compar); 
void qsort(void* base, size_t nmemb, size_t size, __compar_fnp_cxx compar); 

它應該更明顯,__compar_fnp_c__compar_fnp_cxx是不同的類型。也就是說,as-if規則不允許這種實現,因爲它會破壞需要指針或引用到qsort的代碼。

請注意,GCC以及其他一些編譯器不能正確實現這一點,也不會將鏈接視爲函數指針類型的一部分。在這樣的實現中,只有一個版本的qsort可用,以防止重載解決期間的衝突。

+0

我不太確定函數指針的鏈接是否是其類型簽名的一部分。說,我不知道如何在函數指針聲明中指定鏈接。模仿你使用的typedef語法,我在g ++和clang ++中都得到了像'extern「C」int(* p)(int);'這樣的聲明的編譯錯誤。 – goodbyeera

+0

@goodbyeera你在那裏使用的確切線在我的系統上分別被g ++和clang ++所接受,版本分別爲4.8.2和3.4。 (編輯)如果你嘗試使用局部變量聲明,那麼你是對的,語法不允許這樣做。對於塊範圍聲明或定義,語法不允許以任何方式指定函數指針的類型。您需要使用文件範圍typedef,並在您的本地變量中使用該typedef。 – hvd

+0

@goodbyeera我編輯了我的評論,以解決這個問題,幾乎在你發佈你的新評論的同時:) – hvd