2011-12-25 85 views
1

我想知道如果將double (*)(double)轉換爲double(*)(...)是安全的,這將用於推廣可能具有指向多個函數的代碼。C++:將指針轉換爲函數是否安全?

到目前爲止我已經存儲了每個要傳遞給函數的東西,我想知道是否有一種方法可以在函數中調用一個函數(同時傳遞正確數量的參數)廣義的代碼?我的意思是這樣的東西:

//while initializing 
mFunction = sin; 
//later in code 
double (*generalized)(...) = mFunction; 
for(i=0;i<args.size();i++) 
    pusharg(args[i]); 
call(generalized); 

- 編輯 -

如果沒有使用C++是有可能saftly調用使用匯編的功能做一個有效的方法是什麼?

+0

好吧,它不是!我試圖從「指向函數的指針」轉換爲「指向具有其他簽名的函數的指針」,而他試圖將「void *」投射到「函數指針」 – Ali1S232 2011-12-25 13:46:23

回答

3

您不能直接指定double(*)(double)double(*)(...),但您可以reinterpret_cast它。鑄造是明確§5.2.10[expr.reinterpret.cast]/6允許的,但在調用函數澆鑄指針將導致未定義的行爲:

函數指針可以顯式轉換爲一個函數指針不同的類型。

通過指向與函數定義中使用的類型不同的函數類型的指針調用函數的效果是undefined

除該類型的prvalue轉換「指針T1」的類型「指針T2」(其中T1T2是功能類型),並且返回到其原始類型產生了原始指針值,結果這種指針轉換是未指定的。

很容易看出爲什麼會導致UB - 如果我們打電話給generalized(1.0, 2.0, 3.0)?這可能會破壞調用堆棧。但是,如果您在致電generalized之前將其恢復爲double(*)(double),那麼沒關係。

+0

,因爲它是私人成員,所以我不需要擔心可能的程序員錯誤。所以如果我將'sin(double)'轉換爲'generalize(double,...)',我只會調用'generalize(1.0)'或者'hypot(double,double)''我可以確保只調用'generalize(1.0,2。0)' – Ali1S232 2011-12-25 17:52:21

+0

@Gajet:如果可能的話,最好還是回到原始類型以避免錯誤。 '...'可能會改變調用約定(例如,如果你將'float'傳遞給'''參數,它將在調用函數之前轉換爲'double')。 – kennytm 2011-12-25 17:57:47

1

是的,鑄件本身是允許的。但是,用錯誤的簽名來調用它並不是。請注意,如果你想要一個通用函數指針,最好使用void (*)(),它就像函數指針的void*(儘管如此,沒有隱式轉換)。

甚至更​​好,因爲你提供了特定的參數,使用std::functionstd::bind(如果你的編譯器支持C++ 11庫)或它們的Boost等價物。

+0

「_注意,如果你想要一個泛型函數指針,最好使用'void(*)()'_「我寧願使用一個無法調用的指針,比如'void(*)(boost :: noncopyable)'。 – curiousguy 2011-12-25 14:08:41

+0

是否有一個等同的彙編代碼,爲我做的伎倆? – Ali1S232 2011-12-25 17:54:00

+0

@Gajet:我敢肯定,你知道,裝配很不合適。這將是可能的,但。我用自己的委託類實現了它,因爲調用代碼基本上變成了幾條裝配線。但請注意,這是非常麻煩,可能會導致問題。 – Xeo 2011-12-25 20:48:12

0

製作generalized volatile將要求編譯器遵循ABI規範。由於希望支持未聲明的C函數,所以如果不調用除了可變數量的參數之外的函數(儘管指針具有固定數量的參數),這對大多數ABI(包括x86和x86-32)都是安全的。