2009-05-08 9 views
13

Sto creando un C api che nasconde alcune funzionalità in un file DLL.Il tipo giusto per le maniglie nelle interfacce C

Poiché tutto è C++ all'interno, la maggior parte delle funzioni funziona contro gli handle che si mappano direttamente a questi puntatori all'interno dell'API.

Per ottenere un certo grado di sicurezza tipo per quelle maniglie io li definisco così:

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

Io in realtà non definisco MyType1 o MyType2 in qualsiasi luogo da quando li uso solo come puntatori e fare un digitare il cast all'interno della API per il tipo di puntatore effettivo.

mio problema è che quando si utilizza la mia libreria in un progetto CLR in Visual Studio ottengo questo warning: unresolved typeref token (token) for 'type'; image may not run.

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

E 'un grosso problema dal momento che funziona, ma sembra poco professionale.

non mi piace usare void *:

typedef void* MyType1Handle; 
typedef void* MyType2Handle; 

Ciò consente di chiamare una funzione vogliono un MyType1Handle con MyType2Handle dal momento che sono in realtà lo stesso tipo.

Un altro approccio che non voglio usare è qualcosa di simile

typedef int MyType1Handle; 
typedef int MyType2Handle; 

Questo potrebbe funzionare bene finché int di e puntatori hanno la stessa dimensione, ma che non è sempre il caso e sembra che ci non è un metodo infallibile per ottenere un intero di dimensioni puntatore specifico per piattaforma. Ha lo stesso tipo di problemi di sicurezza del vuoto * pure.

Un altro approccio che ho provato era di farlo in questo modo:

struct MyType1{}; 
typedef struct MyType1* MyType1Handle; 

Questo non ha funzionato in C rispetto struct vuote è il codice C valido. Naturalmente potrei estendere la mia struttura con un membro fittizio, ma sembra che ci dovrebbe essere un modo migliore per farlo.

Quindi la mia domanda si riduce a:

Come generalmente si specifica questo tipo di tipi nel modo più compatibile?

risposta

12

Se si guarda a come Microsoft definisce sia le maniglie WinAPI (Winnt.h) in realtà si presenta così:

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

in realtà essi hanno una macro per questo:

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

così. sembra essere una pratica comune farlo. Purtroppo non posso fare un altro suggerimento tranne questo, che hai già menzionato , ma spero che ti aiuti comunque.

+0

Grazie per la risposta. Sembra che non sia il primo ad avere questo problema atleast :) – Laserallan

+0

Una differenza qui è che nelle intestazioni pubbliche, il tipo HANDLE fa riferimento a un tipo concreto. La struttura finta è completamente definita. Ovviamente, definiscono DECLARE_HANDLE in modo diverso quando includono questi file nell'implementazione. – RBerteig

3

penso che si può solo dichiarare, ma non definisce le strutture di origine:

struct MyType1;

typedef struct MyType1 * MyType1Handle;

8

Utilizzare una struttura opaca. Questa è una buona idea in molti casi quando si definisce l'interfaccia di una libreria in C: migliora la modularità, nasconde i dettagli non necessari

Come ha detto JamieH, si ottiene una struttura opaca dichiarando - ma non definendo - una struttura. È perfettamente valido avere e passare i puntatori alla struttura opaca nelle funzioni delle librerie come argomenti e restituirli come valori. Gli utenti della libreria tuttavia non possono creare o modificare oggetti della struttura opaca poiché la sua dimensione e il suo contenuto sono sconosciuti.

La libreria C standard e molti altri usano già questo approccio, quindi dovrebbe essere familiare. L'esempio cannonico è l'uso di FILE *: fopen() crea e inizializza la struttura e restituisce un puntatore ad esso, fclose() pulisce e rilascia e tutte le altre funzioni di I/O ottengono il loro contesto dal passato in FILE *.

+0

I puntatori nascosti nei typedef spesso richiedono problemi (parlando di un messaggio di errore che balbetta qualcosa sui puntatori anche se il tuo programma non sembra usarli o viceversa); quindi l'approccio HWND sopra non posso raccomandare davvero; la struct-definition-not-exposed funziona meglio. Per C++, dal momento che la definizione della classe deve essere resa disponibile affinché le cose funzionino, l'approccio "d-pointer" funzionerebbe meglio qui. – user502515

Problemi correlati