2013-04-15 10 views
10

Wyraźne rzutowanie między wskaźnikami funkcji a wskaźnikami obiektów jest niezdefiniowanym zachowaniem w sensie ogólnym, ale wymaga tego POSIX (patrz: dlsym) i WinAPI (patrz: GetProcAddress).GCC ostrzega o wskaźniku funkcji do wskaźnika obiektu Obsłużenie

Biorąc to pod uwagę i biorąc pod uwagę fakt, że taki kod jest ukierunkowany na API specyficzne dla platformy, jego przenośność na platformy, na których wskaźniki funkcji i wskaźniki obiektów nie są kompatybilne, jest naprawdę nieistotna.

Ale -Wpedantic ostrzega o nim tak, i nie ma żadnego wpływu #pragma GCC diagnostic ignored "-Wpedantic":

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

chcę zachować -Wpedantic włączona, ponieważ daje dobre ostrzeżenia, ale nie chcę aby prawdziwe ostrzeżenia i błędy zostały utracone w morzu nieistotnych ostrzeżeń o wskaźniku funkcji, aby rzucić obiekt po rzutach.

Czy istnieje sposób, aby to osiągnąć?

Running GCC 4.8.0 na Windows (MinGW):

gcc (rubenvb-4.8.0) 4.8.0 

Przykładowy kod

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


int main (void) { 

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

} 

Emitowane (z -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

Nigdy nie miałem problemu z rzuceniem wyniku "GetProcAddress". – chris

+2

Czy masz * kod *, który wygenerował to ostrzeżenie, które możesz opublikować? – WhozCraig

+0

@WhozCraig Dodano do pytania. –

Odpowiedz

3

Myślę, że można używać g ++ 's system_header dyrektywę tutaj:

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'. Dzięki za postawienie mnie na właściwej drodze. –

2

Jest zawsze sztuczka memcpy, której możesz użyć:

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

Możesz to zobaczyć na stronie internetowej: m is generating warnings, while g is OK.

Jeśli chodzi o inny sposób działania, możesz wziąć: Jedną z oczywistych możliwości jest "naprawienie" nagłówka definiującego dlsym w celu zwrócenia wskaźnika funkcji (np. void (*)()). Powodzenia z tym.

+0

Powinieneś przynajmniej static_assert, że wskaźnik funkcji jest wystarczająco duży, aby pomieścić 'void *'. –

+0

Cóż, problem z 'GetProcAddress' staje się tym, co jeśli chcesz uzyskać adres czegoś, co nie jest funkcją w załadowanej bibliotece (zobacz przykład kodu dodany do pytania)? –

+1

@MarkB: Biorąc pod uwagę, że OP chce używać POSIX-a, który faktycznie [wymaga funkcji-wskaźników, aby mieć taką samą reprezentację jak wskaźniki obiektu] (http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html # tag_15_12), uznałbym to za zbędny bałagan (podobny do obsługi 'sizeof (char)' innego niż 1). Ale jeśli czujesz, że go potrzebujesz, możesz go dodać (w takim przypadku wolałbym umieścić go w skrypcie autoconf lub somesuch). – jpalecek

3

to działa prawidłowo.

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); 
} 
Powiązane problemy