2010-05-29 18 views
8

Esiste un modo per verificare se una determinata funzione è dichiarata con C-linkage (ovvero, con extern "C") in fase di compilazione?Verifica se una funzione ha C-linkage in fase di compilazione [irrisolvibile]

Sto sviluppando un sistema di plugin. Ogni plugin può fornire funzioni di fabbrica al codice di caricamento del plugin. Tuttavia, questo deve essere fatto tramite il nome (e l'uso successivo di GetProcAddress o dlsym). Ciò richiede che le funzioni vengano dichiarate con C-linkage in modo da prevenire il manomissione dei nomi. Sarebbe bello essere in grado di lanciare un errore del compilatore se la funzione di riferimento è dichiarata con C++ - linkage (al contrario di scoprire a runtime quando una funzione con quel nome non esiste).

Ecco un esempio semplificato di ciò che intendo:

extern "C" void my_func() 
{ 
} 

void my_other_func() 
{ 
} 

// Replace this struct with one that actually works 
template<typename T> 
struct is_c_linkage 
{ 
    static const bool value = true; 
}; 

template<typename T> 
void assertCLinkage(T *func) 
{ 
    static_assert(is_c_linkage<T>::value, "Supplied function does not have C-linkage"); 
} 

int main() 
{ 
    assertCLinkage(my_func); // Should compile 
    assertCLinkage(my_other_func); // Should NOT compile 
} 

C'è una possibile implementazione di is_c_linkage che getterebbe un errore di compilazione per la seconda funzione, ma non la prima? Non sono sicuro che sia possibile (anche se potrebbe esistere come estensione del compilatore, cosa che mi piacerebbe sapere ancora). Grazie.

+6

Ho il forte sospetto che questo non possa essere fatto, specialmente non in maniera standard. Domanda interessante, però. –

+2

Non ne sono così sicuro. Ma anche se potesse essere fatto, è abbastanza probabile che GCC non lo supporti, perché non conosce la distinzione di una "C" esterna e di un tipo di funzione "C++" extern. Quindi tratta entrambi i tipi allo stesso modo. –

+0

se si sta andando a conoscenza specifica di implementazione si può anche farlo funzionare per tale implementazione, piuttosto che lanciare un errore –

risposta

2

Sono d'accordo con Jonathan Leffler che questo probabilmente non è possibile in un modo standard. Forse sarebbe un po 'possibile, a seconda del compilatore e della versione pari del compilatore, ma dovresti sperimentare per determinare i possibili approcci e accettare il fatto che il comportamento del compilatore era probabilmente non intenzionale e potrebbe essere "corretto" nelle versioni successive.

Con g++ versione 4.4.4 su Debian Squeeze, ad esempio, si potrebbe essere in grado di sollevare un errore del compilatore per le funzioni che non sono stdcall con questo approccio:

void my_func() __attribute__((stdcall)); 
void my_func() { } 

void my_other_func() { } 

template <typename ret_, typename... args_> 
struct stdcall_fun_t 
{ 
    typedef ret_ (*type)(args_...) __attribute__((stdcall)); 
}; 

int main() 
{ 
    stdcall_fun_t<void>::type pFn(&my_func), 
     pFn2(&my_other_func); 
} 

g++ -std=c++0x non riesce a compilare questo codice, perché :

SO2936360.cpp:17: error: invalid conversion from ‘void ()()’ to ‘void ()()’

linea 17 è la dichiarazione di pFn2. Se mi libero di questa dichiarazione, la compilazione ha esito positivo.

Sfortunatamente, questa tecnica non funziona con cdecl.

0

Per Unix/Linux, che ne dici di analizzare il file binario risultante con "nm" e cercare i nomi dei simboli? Suppongo che non sia quello che intendevi, ma è comunque una specie di tempo di compilazione.

Problemi correlati