2010-05-29 11 views
8

¿Hay alguna manera de verificar si una función dada se declara con enlace C (es decir, con extern "C") en tiempo de compilación?Comprobando si una función tiene enlace C en tiempo de compilación [no se puede resolver]

Estoy desarrollando un sistema de complementos. Cada complemento puede suministrar funciones de fábrica al código de carga del complemento. Sin embargo, esto tiene que hacerse a través del nombre (y el uso posterior de GetProcAddress o dlsym). Esto requiere que las funciones se declaren con enlace C a fin de evitar la manipulación de nombres. Sería bueno poder lanzar un error de compilación si la función referida se declara con enlace C++ (en lugar de descubrir en tiempo de ejecución cuando una función con ese nombre no existe).

Aquí está un ejemplo simplificado de lo que quiero decir:

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 
} 

¿Hay una posible implementación de is_c_linkage que lanzaría un error de compilación para la segunda función, pero no el primero? No estoy seguro de que sea posible (aunque puede existir como una extensión del compilador, que todavía me gustaría saber). Gracias.

+6

Sospecho que esto no se puede hacer, especialmente no de manera estándar. Interesante pregunta, sin embargo. –

+2

No estoy tan seguro de eso. Pero incluso si se pudiera hacer, es bastante probable que GCC no lo soporte, porque no conoce la distinción entre un tipo de función "C" externa y una función "C++" externa. Por lo tanto, trata a ambos tipos de la misma. –

+0

si va a implementar conocimientos específicos, puede hacer que funcione para esa implementación en lugar de arrojar un error –

Respuesta

2

Estoy de acuerdo con Jonathan Leffler en que esto probablemente no sea posible de manera estándar. Tal vez sería posible de alguna manera, dependiendo del compilador e incluso de la versión del compilador, pero tendría que experimentar para determinar posibles enfoques y aceptar el hecho de que el comportamiento del compilador probablemente no fue intencional y podría "arreglarse" en versiones posteriores.

Con g++ versión 4.4.4 en Debian Squeeze, por ejemplo, usted podría ser capaz de elevar un error de compilación para las funciones que no son stdcall con este enfoque:

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 falla al compilar el código, porque :

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

la línea 17 es la declaración de pFn2. Si me deshago de esta declaración, entonces la compilación tiene éxito.

Lamentablemente, esta técnica no funciona con cdecl.

0

Para Unix/Linux, ¿qué tal si analizamos el binario resultante con 'nm' y buscamos nombres de símbolos? Supongo que no es lo que querías decir, pero aún es una especie de tiempo de compilación.

Cuestiones relacionadas