2009-05-08 8 views
13

Estoy creando una API C que oculta algunas funciones en un archivo DLL.El tipo correcto para identificadores en interfaces C

Dado que todo es C++ en su interior, la mayoría de las funciones funcionan contra los identificadores que se asignan directamente a estos punteros en el interior de la API.

Para obtener un cierto grado de seguridad de tipo de dichos mangos de los defino así:

typedef struct MyType1* MyType1Handle; 
typedef struct MyType2* MyType2Handle; 

Yo en realidad no defino MyType1 o MyType2 en cualquier lugar ya que sólo los utilizan como punteros y hacer una escriba cast en el interior de la API para el tipo de puntero real.

Mi problema es que al usar mi biblioteca en un proyecto de CLR en Visual Studio consigo este warning: unresolved typeref token (token) for 'type'; image may not run.

http://msdn.microsoft.com/en-us/library/h8027ys9(VS.80).aspx

No es ningún gran problema ya funciona, pero parece poco profesional.

no me gusta usar void *:

typedef void* MyType1Handle; 
typedef void* MyType2Handle; 

Esto hace que sea posible llamar a una función que desean un MyType1Handle con un MyType2Handle ya que en realidad son del mismo tipo.

Otro enfoque no quiero usar algo como esto

typedef int MyType1Handle; 
typedef int MyType2Handle; 

Esto funcionaría bien siempre y cuando INT y punteros tienen el mismo tamaño, pero eso no es siempre el caso y parece que no hay no es una forma infalible de obtener un entero de tamaño de puntero específico de la plataforma. También tiene los mismos problemas de seguridad tipo que el vacío *.

Otro enfoque que intenté fue hacerlo de esta manera:

struct MyType1{}; 
typedef struct MyType1* MyType1Handle; 

Esto no funcionó en C desde estructuras vacías es el código C válido. Por supuesto, podría extender mi estructura con un miembro ficticio, pero parece que debería haber una mejor manera de hacerlo.

Así que mi pregunta se reduce a:

¿Cómo se especifique lo general este tipo de tipos de la forma más compatible?

Respuesta

12

Si nos fijamos en cómo Microsoft define que es manijas WinAPI (WINNT.H) que realmente se ve así:

struct HWND__ { int unused; }; typedef struct HWND__ *HWND 

De hecho, tienen una macro para esto:

#define DECLARE_HANDLE(name) struct name##__{int unused;}; typedef struct name##__ *name 

manera. Esto parece ser una práctica común para hacerlo. Lamentablemente no puedo hacer otra sugerencia, excepto esta, que ya mencionó , pero espero que lo ayude de todos modos.

+0

Gracias por la respuesta. Parece que no soy el primero en encontrarme con este problema al menos :) – Laserallan

+0

Una diferencia aquí es que en los encabezados públicos, el tipo HANDLE hace referencia a un tipo concreto. La estructura falsa está completamente definida. Por supuesto, definen DECLARE_HANDLE de forma diferente al incluir esos archivos en la implementación. – RBerteig

3

Creo que sólo se puede declarar, pero no definen, las estructuras de origen: MyType1

estructura;

typedef struct MyType1 * MyType1Handle;

8

Utilice una estructura opaca. Esta es una buena idea en muchos casos cuando se define la interfaz de una biblioteca en C: mejora la modularidad, oculta detalles innecesarios

Como dijo JamieH, obtienes una estructura opaca al declarar -pero no definir- una estructura. Es perfectamente válido tener, y pasar, punteros a la estructura opaca en las funciones de las bibliotecas como argumentos y devolverlos como valores. Sin embargo, los usuarios de la biblioteca no pueden crear o modificar objetos de la estructura opaca ya que su tamaño y contenido son desconocidos.

La biblioteca estándar C, y muchas otras, ya utilizan este enfoque, por lo que debe ser familiar. El ejemplo canónico es el uso de FILE *: fopen() crea e inicializa la estructura y devuelve un puntero al mismo, fclose() lo limpia y lo libera y todas las otras funciones de E/S obtienen su contexto del pasado en FILE *.

+0

Ocultar punteros en typedefs a menudo requiere problemas (al hablar de un mensaje de error que balbucea algo sobre punteros, incluso si su programa no parece usarlos o viceversa); entonces el enfoque de HWND arriba no puedo recomendar realmente; la estructura-definición-no-expuesta funciona mejor. Para C++, dado que la definición de clase debe estar disponible para que las cosas funcionen, el enfoque "d-puntero" funcionaría mejor aquí. – user502515

Cuestiones relacionadas