2013-04-15 130 views
10

函數指針和對象指針之間顯然鑄造是一般意義上的不確定的行爲,但POSIX(參見:dlsym)和WinAPI的(參見:GetProcAddress)要求這一點。GCC發出警告函數指針對象的指針鑄造

鑑於此,並且考慮到此類代碼無論如何都針對特定於平臺的API,因此其對於函數指針和對象指針不兼容的平臺的可移植性實際上是無關緊要的。

-Wpedantic警告一下也無妨,而且#pragma GCC diagnostic ignored "-Wpedantic"沒有影響:

warning: ISO C++ forbids casting between pointer-to-function and pointer-to-object [enabled by default] 

我想保持-Wpedantic啓用,因爲它提供良好的警告,但我不希望在有關指向對象指針轉換的函數指針的無關警告的海洋中,失去真正的警告和錯誤。

有沒有辦法做到這一點?

在Windows(MinGW的)運行GCC 4.8.0:

gcc (rubenvb-4.8.0) 4.8.0 

代碼示例

#include <windows.h> 
#include <iostream> 


int main (void) { 

    std::cout << *reinterpret_cast<int *>(GetProcAddress(LoadLibraryA("test.dll"),"five")) << std::endl; 

} 

發出(與-Wpedantic):

warning_demo.cpp: In function 'int main()': 
warning_demo.cpp:7:87: warning: ISO C++ forbids casting between pointer-to-funct 
ion and pointer-to-object [enabled by default] 
    std::cout << *reinterpret_cast<int *>(GetProcAddress(LoadLibraryA("test.dll"), 
"five")) << std::endl; 

    ^
+0

我從來沒有遇到過轉換'GetProcAddress'的結果的問題。 – chris

+2

您是否有任何* code *產生了您可以發佈的警告? – WhozCraig

+0

@WhozCraig添加到問題。 –

回答

3

我想你可以使用G ++的system_header指令這裏:

wrap_GetProcAddress.h:

#ifndef wrap_GetProcAddress_included 
#define wrap_GetProcAddress_included 

#pragma GCC system_header 

template <typename Result> 
Result GetProcAddressAs([normal parameters]) 
{ 
    return reinterpret_cast<Result>(GetProcAddressAs([normal parameters])); 
} 

#endif 
+0

'#pragma GCC system_header'。感謝您讓我走上正軌。 –

2

有總是你可以使用的memcpy技巧:

int (*f)() = 0; 
int *o; 
memcpy(&o, &f, sizeof(int*)); 

你可以在ideone上看到它:m is generating warnings, while g is OK

至於其他行動當然,你可能要考慮:一個明顯的可能是,「固定」定義dlsym實際返回一個函數指針(如void (*)())的頭。祝你好運。

+0

您至少應該static_assert函數指針足夠大以容納'void *'。 –

+0

那麼'GetProcAddress'的問題就變成了什麼,如果你想要得到的東西不是你裝載的函數庫中的函數的地址(請參閱我添加到問題中的代碼示例)? –

+1

@MarkB:鑑於OP要使用POSIX,實際上[需要函數指針與對象指針具有相同的表示](http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html #tag_15_12),我認爲它是一個多餘的混亂(類似於處理'sizeof(char)'不同於1)。但如果你覺得你需要它,你可以添加它(在這種情況下,我寧願把它放到一個autoconf腳本或其他)。 – jpalecek

3

這工作得很好。

template <typename RESULT, typename ...ARGS> 
void * make_void_ptr(RESULT (*p)(ARGS...)) { 
    static_assert(sizeof(void *) == sizeof(void (*)(void)), 
        "object pointer and function pointer sizes must equal"); 
    void *q = &p; 
    return *static_cast<void **>(q); 
}