2011-12-11 287 views
2

(5.2.10/6)C++ 03指向函數的指針可以顯式轉換爲指向不同類型函數的指針。通過一個指向函數類型(8.3.5)調用函數 的效果是不一樣的 在函數的定義中使用的類型是未定義的。除了 該類型的右值轉換「指針T1」的類型「指針 到T2」(其​​中,T1和T2是功能類型),並且返回到其原始 類型產生的原始指針值,這樣的指針的結果 轉換未指定。 [注:也見4.10爲 指針轉換詳情]將函數指針轉換爲指向函數類型的指針的結果

以下是我想要做的,而很顯然,轉換fp1fp2的結果會產生一個原始的指針,但在同一時間標準的措辭是"The result of such a pointer conversion is unspecified"這是什麼意思?

int f() { return 42; } 

int main() 
{ 
    void(*fp1)() = reinterpret_cast<void(*)()>(f); 

    int(*fp2)() = reinterpret_cast<int(*)()>(fp1); 

    // Safe to call the function ? 
    fp2(); 
} 

回答

5

您誤讀標準中,「未指定」部分僅適用於其他類型的轉換:

除[特例]這樣的指針轉換的結果是不確定的。

[特殊情況]是你轉換回原來的函數指針類型,就像你的例子。在這種特殊情況下,轉換會產生原始指針值,所以可以像在你的例子中那樣使用它。

僅用於其他轉換,結果未指定。

+0

我想其他的轉換就像'f'到'fp1'在我的情況下,對嗎? – user1086635

+0

@user:是的,沒有指定'fp1'的內容,但是如果您轉換回原始類型,則會返回原始值。 – sth

+0

未定義的行爲是,如果你試圖做'(* fp1)();'。這會調用一個返回'int'的函數,就像它返回'void'一樣。至少這取決於你的架構的ABI。如果它使用舊的C方法,在調用函數之前爲堆棧中返回的對象分配空間,那麼在這種情況下,它不會爲返回的「int」分配空間(因爲它認爲沒有返回值),並且被調用的函數會將其返回值放在錯誤的地方(例如覆蓋返回地址),並且事情從此處下坡。 –

4

是的,你很安全。你正在做的是「除了轉換......」情況。

的原因,這就是所謂的出來是爲了讓你通過另一種類型的函數指針的傳遞函數指針。所以,你可以定義是這樣的:

enum CallbackType { 
    eFuncPtrVoidReturningVoid, 
    eFuncPtrVoidReturningInt, 
    // ... more as needed ... 
}; 

class CallbackRecord 
{ 
public: 
    CallbackRecord(void (*cb)()): cbType(eFuncPtrVoidReturningVoid), cbFunc(cb) 
     {} 
    CallbackRecord(int (*cb)()): cbType(eFuncPtrVoidReturningInt), 
     cbFunc(reinterpret_cast<void (*)()>(cb)) {} 
    void operator()() const; 
protected: 
    CallbackType cbType; 
    void (*cbFunc)(); 
}; 

void CallbackRecord::operator()() const 
{ 
    switch(cbType) 
    { 
    case eFuncPtrVoidReturningVoid: 
     (*cbFunc)(); 
     break; 

    case eFuncPtrVoidReturningInt: 
     while((*reinterpret_cast<int (*)()>(cbFunc))()) 
      ; 
     break; 
    } 
} 

雖然你可以只說「讓所有的回調返回int」,這將要求你寫的東西包裝不符合調用約定,如果回調類型的數字變超過兩個。允許這些函數指針類型轉換爲您提供了一種支持多種回調類型的替代方法,並使我們不需要將CallbackRecord轉換爲模板。它還允許繼承或編組來替代上面的switch聲明,而不需要使用virtual方法。

5

是的,它是安全的。
reinterpret_cast只允許在一個指針轉換爲另一種,但它並不能保證,除非它被強制轉換-ED恢復到原來的任何類型的安全性和使用這種指針的結果是不確定的。

提到的標準報價規定,如果強制轉換一個類型的函數指針爲另一種類型,並試圖通過它來調用一個函數,那麼結果是不確定的。

但是,
reinterpret_cast保證您如果將類型轉換指針轉換回原始類型,則指針結構良好。

你的代碼試圖做第二次,因此它是安全的。

相關問題