2015-07-20 105 views
2

如何是下面的函數指針分配:鑄造在函數指針分配

exit = (void (*)()) &jump; 

不同從:

exit = &jump; 

出口是一個函數指針定義,其中爲:

void (*exit)(); 

和'跳'是一個函數,聲明爲:

void jump(); 
+2

什麼是'exit'和什麼是'jump'? –

+0

@VladfromMoscow:謝謝! – talha099

回答

9
exit = (void (*)()) &jump; 

第一個使用強制鑄造。這很危險,因爲它可能會讓程序搞砸而不讓你知道類型是否匹配,因爲它不會在編譯時被捕獲。

所以,如果你是這樣做:

int func() {return 1;} 
auto exit = (void (*)()) &func; 

...這將是糟糕的。然而,它的更好,如果你這樣做了如下:

exit = &jump; 

第二個使用了編譯時類型檢查。這樣更安全,因爲編譯器會在編譯時檢查類型這給你一個更強大的類型保證。

最好的選擇是使用static_cast<void(*)()>它是類型安全的,它告訴程序員更多你想要做什麼的意圖。

auto exit = static_cast<void(*)()>(&func); 

如果你有C++,你可以試試下面的事情:

如果你不想類型關心自己,用auto

auto exit = &func

這將確保類型將匹配。 如果你要檢查的類型,使用typeid().name<typeinfo>存在於C++ 11及更高版本:

std::cout << typeid(exit).name << std::endl; 

雖然這通常給出了功能一些奇怪的輸出,你可能會發現一些信息,可以幫助你,如果兩種類型不同,最好的一種。

這裏的顯示在運行時與函數指針鑄造這一問題的工作例如:http://coliru.stacked-crooked.com/a/47f74e8b6f389812

+0

讀者可以通過學習如何使用適當的C++類型轉換來緩解您的第一點和第二點。如果被編譯器檢測爲無效,嘗試使用static_cast將會失敗;如果應用於第二個,它將確保這個以及程序員的信號意圖。儘可能避免使用C風格的演員陣容。 (所以應該拋棄,但C++提供了更好的集合。) –

+0

@underscore_d我們不應該將自己限制在C++中。這個問題被標記爲兩個。 – VermillionAzure

+0

公平點,但同樣,我們也不應該將自己侷限於C!我的評論爲您的答案中未提供的C++方面提供了一個選項。 –

0

這兩個作業有相同的效果。第一種方法是將「&jump」投射到一個指向不帶參數的函數的指針,並返回void,但&jump已經是那個了!

+0

評論請問,downvoter? –

+0

在大多數情況下它們並不相同,儘管這個例子並沒有產生不同的結果,但重要的是要突出使用這兩個互換的錯誤。 – VermillionAzure

+0

@VermillionAzure相對於來自問題的代碼示例,它們是相同的。 –

3

他們都非常相似。

在C中,如果函數和類型是精確描述:

void (*exit)(); 
void jump(); 
exit = (void (*)()) &jump; 
exit = &jump; 

是相同的。

現在,當我改變會發生什麼jump

int jump(); 

我們現在正在運行的不確定的行爲,也沒有發生錯誤或警告,如果我們調用後exit

exit = (void (*)()) &jump; 

但在這裏我們得到一個類型錯誤:

exit = &jump; 

此外,更微妙的di可能會發生fference - 例如jump可能會得到一個調用約定,因此無法存儲在exit中,事情就會中斷。

在C++中,還有一個細微的差別。如果jump是一個重載函數,退出不是一個原始函數指針(但是,比如說,一個std::function<void()>),第一個可以編譯,而第二個可能不會。將名稱轉換爲函數指針類型可以觸發重載解析,如果沒有它,某些代碼將無法工作。

但是,使用static_cast<void(*)()>會更安全。

+0

你寫的是真的,但實際上,我知道沒有硬件體系結構調用通過void(*)()返回int的函數可能會導致問題。有一些低級任務需要做這樣的事情。 – ach

+0

@AndreyChernyakhovskiy * nod *,你需要一個基於堆棧的返回值(而不是寄存器)來清理一個'int'的被調用者。或者可能是一個調用者清理,其中被調用的代碼需要一些空間來填充'int',並且它沒有計劃(因爲它應該返回'void')。事實是,大多數'int'大小的返回值顯示在寄存器中,通常在函數不應該保存的寄存器中,使不良行爲不太可能發生。 – Yakk

+0

@AndreyChernyakhovskiy編譯器可以看到'void'函數沒有返回值,所以使用通常用於返回'int'的寄存器來保存一個值,該值不會被函數調用 –