2013-04-15 31 views
10

Il casting tra puntatori di funzione e puntatori di oggetti è un comportamento non definito in senso generale, ma POSIX (vedere: dlsym) e WinAPI (vedere: GetProcAddress) richiedono questo.GCC segnala puntatore funzione puntatore oggetto Cast

Dato questo, e dato il fatto che tale codice ha come target un'API specifica per piattaforma, la sua portabilità su piattaforme in cui puntatori di funzione e puntatori di oggetti non sono compatibili è davvero irrilevante.

Ma -Wpedantic avverte su di esso in ogni caso, e #pragma GCC diagnostic ignored "-Wpedantic" non ha alcun effetto:

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

voglio mantenere -Wpedantic abilitata, dal momento che dà buoni avvertimenti, ma non voglio di avere avvertimenti e errori reali persi in mezzo a un mare di avvisi irrilevanti sul puntatore di funzione ai cast del puntatore dell'oggetto.

C'è un modo per realizzare questo?

esecuzione GCC 4.8.0 su Windows (MinGW):

gcc (rubenvb-4.8.0) 4.8.0 

codice di esempio

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


int main (void) { 

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

} 

Emette (con -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

Non ho mai avuto un problema con il cast del risultato di "GetProcAddress'. – chris

+2

Hai qualche * codice * che ha generato quell'avvertenza che puoi postare? – WhozCraig

+0

@WhozCraig Aggiunto alla domanda. –

risposta

3

Penso che si potrebbe usare g 's ++ system_header direttiva qui:

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'. Grazie per avermi messo sulla strada giusta. –

2

C'è sempre il trucco memcpy che puoi usare:

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

Si può vedere su ideone: m is generating warnings, while g is OK.

Per quanto riguarda altro corso di azione che si potrebbe desiderare di prendere: Una possibilità ovvia sarebbe quella di "fissare" l'intestazione definendo dlsym di tornare in realtà un puntatore a funzione (come void (*)()). Buona fortuna.

+0

Si dovrebbe almeno static_assert che un puntatore a funzione sia abbastanza grande da contenere un 'void *'. –

+0

Bene, il problema con 'GetProcAddress' diventa quindi quello che succede se si desidera ottenere l'indirizzo di qualcosa che non è una funzione nella libreria caricata (vedere l'esempio di codice che ho aggiunto alla domanda)? –

+1

@MarkB: Dato che l'OP vuole usare POSIX, che in realtà [richiede che i puntatori di funzione abbiano la stessa rappresentazione dei puntatori di oggetti] (http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html # tag_15_12), lo considererei un disordine superfluo (simile alla gestione di 'sizeof (char)' diverso da 1). Ma se ritieni di averne bisogno, puoi aggiungerlo (nel qual caso preferirei inserirlo in uno script autoconf o somesuch). – jpalecek

3

Questo funziona bene.

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); 
}