Reglas generales y limitaciones
Específicos de Microsoft
Si declara una función o un objeto sin el atributo
dllimport
odllexport
, la función o el objeto no se consideran parte de la interfaz DLL. Por consiguiente, la definición de la función o el objeto debe estar presente en ese módulo o en otro módulo del mismo programa. Para que una función o un objeto formen parte de la interfaz DLL, debe declarar la definición de la función o del objeto en el otro módulo comodllexport
. De los contrario, se genera un error del vinculador.Si declara una función o un objeto con el atributo
dllexport
, su definición debe aparecer en algún módulo del mismo programa. De los contrario, se genera un error del vinculador.Si un solo módulo del programa contiene declaraciones
dllimport
ydllexport
para la misma función u objeto, el atributodllexport
tiene prioridad sobre el atributodllimport
. Sin embargo, se genera una advertencia del compilador. Por ejemplo:__declspec( dllimport ) int i; __declspec( dllexport ) int i; // Warning; inconsistent; // dllexport takes precedence.
En C++, puede inicializar un puntero de datos local estático o declarado globalmente o con la dirección de un objeto de datos declarado con el atributo
dllimport
, lo que genera un error en C. Además, puede inicializar un puntero de función local estático con la dirección de una función declarada con el atributodllimport
. En C, esta asignación establece el puntero en la dirección del código thunk de importación de DLL (un código auxiliar que transfiere el control a la función) en lugar de en la dirección de la función. En C++, establece el puntero en la dirección de la función. Por ejemplo:__declspec( dllimport ) void func1( void ); __declspec( dllimport ) int i; int *pi = &i; // Error in C static void ( *pf )( void ) = &func1; // Address of thunk in C, // function in C++ void func2() { static int *pi = &i; // Error in C static void ( *pf )( void ) = &func1; // Address of thunk in C, // function in C++ }
Aun así, como un programa que incluya el atributo
dllexport
en la declaración de un objeto debe proporcionar la definición de ese objeto en alguna parte del programa, puede inicializar un puntero de función estático global o local con la dirección de una funcióndllexport
. De igual forma, puede inicializar un puntero de datos estático global o local con la dirección de un objeto de datosdllexport
. Por ejemplo, el código siguiente no genera errores en C ni en C++:__declspec( dllexport ) void func1( void ); __declspec( dllexport ) int i; int *pi = &i; // Okay static void ( *pf )( void ) = &func1; // Okay void func2() { static int *pi = &i; // Okay static void ( *pf )( void ) = &func1; // Okay }
Si se aplica
dllexport
a una clase normal que tiene una clase base que no está marcada comodllexport
, el compilador generará la advertencia C4275.El compilador genera la misma advertencia si la clase base es una especialización de una plantilla de clase. Para solucionar este problema, marque la clase base con
dllexport
. El problema con una especialización de una plantilla de clase es dónde colocar__declspec(dllexport)
; no se permite marcar la plantilla de clase. En lugar de ello, cree explícitamente una instancia de la plantilla de clase y marque esta instancia explícita condllexport
. Por ejemplo:template class __declspec(dllexport) B<int>; class __declspec(dllexport) D : public B<int> { // ...
Esta solución no funciona si el argumento de la plantilla es la clase de la que se deriva. Por ejemplo:
class __declspec(dllexport) D : public B<D> { // ...
Como este es un patrón común con plantillas, el compilador cambió la semántica de
dllexport
cuando se aplica a una clase que tiene una o más clases base y cuando una o más de las clases base es una especialización de una plantilla de clase. En este caso, el compilador aplica implícitamentedllexport
a las especializaciones de plantillas de clase. Puede hacer lo siguiente y no recibir una advertencia:class __declspec(dllexport) D : public B<D> { // ...
FIN de Específicos de Microsoft