18 Stimmen

Der richtige Typ für Handles in C-Schnittstellen

Ich erstelle eine C-Api, die einige Funktionen in einer DLL-Datei versteckt.

Da alles in C++ ist, arbeiten die meisten Funktionen mit Handles, die direkt auf diese Zeiger im Inneren der API abgebildet werden.

Um ein gewisses Maß an Typsicherheit für diese Griffe zu erhalten, definiere ich sie wie folgt:

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

Ich definiere MyType1 oder MyType2 an keiner Stelle, da ich sie nur als Zeiger verwende und einen Typ-Cast auf der Innenseite der API auf den tatsächlichen Zeigertyp durchführe.

Mein Problem ist, dass bei der Verwendung meiner Bibliothek in einem Clr-Projekt in Visual Studio ich diese erhalten warning: unresolved typeref token (token) for 'type'; image may not run.

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

Es ist keine große Sache, da es funktioniert, aber es sieht unprofessionell aus.

Ich mag es nicht, void* zu verwenden:

typedef void* MyType1Handle;
typedef void* MyType2Handle;

Dadurch ist es möglich, eine Funktion, die einen MyType1Handle benötigt, mit einem MyType2Handle aufzurufen, da sie tatsächlich vom gleichen Typ sind.

Ein anderer Ansatz, den ich nicht verwenden möchte, ist etwa so

typedef int MyType1Handle;
typedef int MyType2Handle;

Dies würde gut funktionieren, solange ints und Zeiger die gleiche Größe haben, aber das ist nicht immer der Fall, und es scheint, wie es keine narrensichere Möglichkeit, eine plattformspezifische Zeigergröße Integer zu erhalten. Es hat die gleichen Probleme mit der Typsicherheit wie die void* sowie.

Ein anderer Ansatz, den ich ausprobiert habe, war folgender: Ich habe es so gemacht:

struct MyType1{};
typedef struct MyType1* MyType1Handle;

Dies funktionierte in C nicht, da leere Strukturen ungültiger C-Code sind. Ich könnte natürlich meine Struktur mit einem Dummy-Mitglied erweitern, aber es scheint, wie es eine bessere Möglichkeit, dies zu tun sein sollte.

Meine Frage läuft also auf Folgendes hinaus:

Wie spezifizieren Sie diese Art von Typen im Allgemeinen auf die kompatibelste Weise?

14voto

lx. Punkte 2287

Wenn Sie sich ansehen, wie Microsoft seine Winapi-Handles definiert (winnt.h), sieht es tatsächlich so aus:

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

Es gibt sogar ein Makro für diese Funktion:

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

Dies scheint also eine gängige Praxis zu sein. Leider kann ich keinen anderen Vorschlag machen als den, den Sie bereits erwähnt haben. erwähnt haben, aber ich hoffe, er hilft Ihnen trotzdem.

8voto

Wuggy Punkte 286

Verwenden Sie eine undurchsichtige Struktur. Dies ist in vielen Fällen eine gute Idee, wenn man die Schnittstelle zu einer Bibliothek in C definiert: es verbessert die Modularität, verbirgt unnötige Details

Wie JamieH sagte, erhalten Sie eine undurchsichtige Struktur, indem Sie eine Struktur deklarieren - aber nicht definieren -. Es ist vollkommen zulässig, Zeiger auf die opaque struct in den Funktionen der Bibliothek als Argumente zu haben und sie als Werte zurückzugeben. Benutzer der Bibliothek können jedoch keine Objekte der opaque struct erstellen oder verändern, da ihre Größe und ihr Inhalt unbekannt sind.

Die C-Standardbibliothek und viele andere verwenden diesen Ansatz bereits, er sollte also bekannt sein. Das kanonische Beispiel ist die Verwendung von FILE * : fopen() erstellt und initialisiert die Struktur und gibt einen Zeiger auf sie zurück, fclose() aufräumt und freigibt, und alle anderen E/A-Funktionen erhalten ihren Kontext von der übergebenen FILE * .

3voto

JamieH Punkte 1217

Ich glaube, Sie können die Quellstrukturen nur deklarieren, aber nicht definieren:

struct MyType1;

typedef struct MyType1* MyType1Handle;

1voto

Nawaz Punkte 339767

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X