2010-06-04 20 views
6

Estoy tratando de comprender mejor las funciones C externas.mejor comprensión de las funciones externas "C"

Según mi conocimiento, una función C externa siempre es una función a la que está intentando llamar desde una aplicación que ya se ha compilado. Ya sea una biblioteca ejecutable, estática o dinámica.

extern "C" 
{ 
    HRESULT CreateDevice(); 
    typedef HRESULT (*CREATEDEVICE)(); 

    HRESULT ReleaseDevice(); 
    typedef HRESULT (*RELEASEDEVICE)(); 
} 

Así que mi pregunta es ...

es mi entendimiento correcto ??

¿Siempre tiene que ser un puntero de función C? '

¿Por qué debe usar un typedef para cada función?

Supongo que cuando usa GetProcAddress(). Está asignando memoria a las aplicaciones de datos HEAP y no a la que está llamando. Por lo tanto, debe liberarlo de ese montón también?

+0

¿Has visto esta pregunta? http://stackoverflow.com/questions/67894/why-do-we-need-extern-c-include-foo-h-in-c – Jujjuru

Respuesta

1

No tiene que ser un puntero a la función. Puede especificar la declaración de la función normalmente y prefijarla con extern "C", como se muestra en some Microsoft examples.

Si usa GetProcAddress(), no está asignando memoria. Simplemente obtiene la dirección de memoria de la función dentro de la DLL que ya se ha cargado en la memoria (con LoadLibrary(), presumiblemente).

incluso cuando se utilizan punteros de función (como los devueltos por GetProcAddress) no tiene utilizar typedef, es sólo que el código se ve muy fea sin ella. Siempre es difícil averiguar qué escribir también. Creo que sería algo así como:

void (*pReleaseDevice)() = (void (__cdecl *)(void))GetProcAddress(hInstance, "ReleaseDevice"); 
+0

Tenga en cuenta que __cdecl es específico de Microsoft. –

+2

@Billy ONeal: así es 'GetProcAddress' y Visual Studio. – dreamlax

+0

GetProcAddress no es específico de Microsoft, pero es específico de Windows. Puedo usar GetProcAddress con MinGW por ejemplo, pero no con __cdecl. –

0

extern "C" {} es una convención de C++ para declarar que las funciones incluidas son funciones de C - no funciones de C++. C++ tiene una convención de nombres ligeramente diferente que entra en conflicto con C. Si tiene una biblioteca escrita en C y desea usarla en un programa C++, debe usar extern "C" {} para que el compilador sepa que se trata de funciones C. Si la biblioteca fue escrita en C++, creo que la "C" {} externa causará un error.

Tenga en cuenta que extern tiene múltiples significados; este caso específico es una convención de C++ y no está relacionado con los diferentes usos de extern. Por ejemplo,

extern int count; 

tiene un significado completamente diferente que extern "C" {}.

typedef está separado del problema externo "C" {}. typedefs le permite crear alias para tipos comunes que tienen más sentido. Por ejemplo, declarar estructuras es a menudo un proceso detallado. Puedo usar un typedef para acortarlo:

struct mystruct {int a; int b}; 
typedef struct mystruct returncode; 
// I can now declare a variable as type 'returncode' 
returncode a; 

Por lo tanto, en su ejemplo el HRESULT es realmente un alias para (* CreateDevice)() aunque yo creo que hay que ponerla antes de la función (y no después) .

4

extern "C" tiene 2 implicaciones. En primer lugar, declara que los nombres simbólicos de las funciones no tienen "nombre mutilado" para admitir C++. En segundo lugar, le dice al compilador que la función se llama utilizando la convención de llamadas C en lugar de la convención de llamadas PASCAL.La diferencia tiene que ver con cuando la dirección de retorno se empuja en la pila. El uso de la convención de llamadas incorrecta bloqueará su aplicación.

Esta declaración es para el compilador, no para el enlazador. Por lo tanto, la función C externa podría existir en sus propios módulos o en una biblioteca binaria: el enlazador resuelve la fuente de los bytes reales para la implementación de la función. Si la firma de la función se declara como una función normal de C++ y no como una C externa, el compilador manipulará el nombre simbólico para codificar la información del tipo de la firma de la función. Esto lo hará incompatible con el código objeto generado por otros compiladores de C++. Por lo tanto, la creación de una función C externa le permite compartir código entre compiladores en forma binaria. Tenga en cuenta que no puede exponer funciones miembro de esta manera, solo funciones C de estilo antiguo.

0

Un aspecto importante de especificar el enlace extern "C" es que los nombres de las funciones no se destruyen, que es el valor predeterminado para los nombres de C++.

Para que las funciones de su biblioteca para poder ser cargado usando GetProcAddress, que tendrá que agregar la función a la .def file, usar o usar __declspec(dllexport)extern "C".

0

Para responder, en orden:

  • extern funciones "C" se utilizan para la interoperabilidad con C de C++. Usarlos tiene la consecuencia de que el código C puede llamar a la función. Como la API de Windows es una API de C, todas las funciones son externas "C" para garantizar que los códigos C y C++ puedan hacer uso de la API.

  • Para que los programas de C++ interactúen con otros idiomas, incluido C, como una convención, las funciones se exportan utilizando extern "C". Por eso, una gran cantidad de código dll hace esto. Sin embargo, no es un requisito técnico.

  • Así que no, NO tiene que ser un puntero de función C.

  • No es necesario que use typedef tampoco.

El código de ejemplo proporcionado proviene de un archivo de encabezado que publica las exportaciones de un archivo DLL dos veces: una vez como el conjunto de métodos "C" externos que se exportan para que el dll pueda vincularse estáticamente. el otro como un conjunto de tipos de puntero a función, de modo que el dll pueda cargarse dinámicamente y los tipos de puntero a función utilizados con GetProcAddress.

Cuestiones relacionadas