2011-06-07 69 views
3

據我所知有型,不兼容的函數指針之間的鑄造,如:鑄造函數指針,以接受更多的參數

void aUnaryFunction(int a1) 
{ 
    /* .... */ 
} 

void doSomethingWithFn() 
{ 
    typedef void(*BinaryFn)(int, const char*); 
    BinaryFn aBinaryFunction = (BinaryFn) &aUnaryFunction; 
    aBinaryFunction (3, "!!!"); 
} 

不應該做,因爲是根據C「未定義行爲」標準。

但是我不明白爲什麼,給定函數調用在C中的工作方式,這個例子是不安全的。我所做的一切都是無視論證。

假設一個int第一個參數的處理是一致的,都認爲會發生的是,爲const char *將被放置在一個寄存器時,doSomethingWithFn()電話aBinaryFunctionaUnaryFunction會按預期運行,併爲const char *可以在在aUnaryFunction期間被覆蓋,但這很好,因爲無論如何沒有別的東西會使用它。

我在這裏錯過了什麼,或者這實際上是安全的嗎? (或兩者之間或兩者之間的東西?)

回答

6

問題是,沒有一個單獨的「方式函數調用工作在C」 - 只有函數調用工作在特定的C實現的方式。

作爲一個具體的例子,調用約定(如x86 stdcall)需要被調用者知道有多少參數被推送到堆棧以執行正確的清理,這在您的示例中將被顛覆。

5

這可以歸結爲調用約定。例如,如果參數是以相反順序「發送」的呢?或者如果在函數調用之後有一個標準過程必須完成,而這個過程依賴於正確的參數個數?

您提出的建議可能有效,但您不應該依賴這一點,並且Standard將其歸因於未定義的行爲。

0

順便說一句,'未定義的行爲'是「不這樣做,它不安全!」的祕密代碼。

這表明它不能在同一臺機器上的不同機器上或相同編譯器的不同版本上工作。