如何是下面的函數指針分配:鑄造在函數指針分配
exit = (void (*)()) &jump;
不同從:
exit = &jump;
出口是一個函數指針定義,其中爲:
void (*exit)();
和'跳'是一個函數,聲明爲:
void jump();
如何是下面的函數指針分配:鑄造在函數指針分配
exit = (void (*)()) &jump;
不同從:
exit = &jump;
出口是一個函數指針定義,其中爲:
void (*exit)();
和'跳'是一個函數,聲明爲:
void jump();
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
讀者可以通過學習如何使用適當的C++類型轉換來緩解您的第一點和第二點。如果被編譯器檢測爲無效,嘗試使用static_cast將會失敗;如果應用於第二個,它將確保這個以及程序員的信號意圖。儘可能避免使用C風格的演員陣容。 (所以應該拋棄,但C++提供了更好的集合。) –
@underscore_d我們不應該將自己限制在C++中。這個問題被標記爲兩個。 – VermillionAzure
公平點,但同樣,我們也不應該將自己侷限於C!我的評論爲您的答案中未提供的C++方面提供了一個選項。 –
這兩個作業有相同的效果。第一種方法是將「&jump
」投射到一個指向不帶參數的函數的指針,並返回void
,但&jump
已經是那個了!
評論請問,downvoter? –
在大多數情況下它們並不相同,儘管這個例子並沒有產生不同的結果,但重要的是要突出使用這兩個互換的錯誤。 – VermillionAzure
@VermillionAzure相對於來自問題的代碼示例,它們是相同的。 –
他們都非常相似。
在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(*)()>
會更安全。
你寫的是真的,但實際上,我知道沒有硬件體系結構調用通過void(*)()返回int的函數可能會導致問題。有一些低級任務需要做這樣的事情。 – ach
@AndreyChernyakhovskiy * nod *,你需要一個基於堆棧的返回值(而不是寄存器)來清理一個'int'的被調用者。或者可能是一個調用者清理,其中被調用的代碼需要一些空間來填充'int',並且它沒有計劃(因爲它應該返回'void')。事實是,大多數'int'大小的返回值顯示在寄存器中,通常在函數不應該保存的寄存器中,使不良行爲不太可能發生。 – Yakk
@AndreyChernyakhovskiy編譯器可以看到'void'函數沒有返回值,所以使用通常用於返回'int'的寄存器來保存一個值,該值不會被函數調用 –
什麼是'exit'和什麼是'jump'? –
@VladfromMoscow:謝謝! – talha099