2017-11-13 3 views
3

In meiner C-Programmierung mit, I opaque-Zeiger verwende als eine Möglichkeit struct Abstraktion und Einkapselung von meinem Code zu erzwingen, in dieser Weise:einen opaken Zeiger auf einen nicht-Typen struct

interface_header.h:

typedef struct s_mytype t_mytype; 

defs_header.h:

struct s_mytype 
{ 
/* Actual definition of the struct */ 
}; 

Mein Problem ich eine einfache Art, wie t_mytype (char zum Beispiel) verwenden möchten, aber nicht informieren die interfa ce darüber. Ich kann nicht einfach typedef char t_mytype verwenden, da das die Interna des Typs freilegen würde. Ich könnte einfach Void-Zeiger verwenden, aber auf Kosten der Typprüfung, und das würde ich lieber vermeiden.

Doing zwei typedef wird auch nicht arbeiten, seit dem eine typedef redefinition with different types aus dem Compiler werfen.

Ich überlege auch, eine Struktur mit nur einem Mitglied zu machen, was mein einfacher Typ sein wird, aber wäre das ein Overkill?

Vielen Dank für Ihre Antworten.

+2

Wenn Sie einen undurchsichtigen Typ benötigen, sind Strukturen erforderlich. Entscheiden Sie, ob Opakheit oder Einfachheit wichtiger ist. Denken Sie daran, dass Sie Zeiger herumreichen werden. –

+2

Verwenden Sie das einzelne Mitglied. Es ist ein bisschen Standard in Ihrer * Quelle *, aber der kompilierte Code sollte nicht anders sein. –

+0

Können Sie etwas Ähnliches tun, wie 'sockaddr' und' sockaddr_in' implementiert werden? – MFisherKDX

Antwort

3

Sie müssen eine Entscheidung treffen. Mit Code wie folgt:

typedef char myHandle; 

frobnicate(myHandle *obj); 

Sie bereits dokumentieren die Absicht, dass Client-Code nur Zeiger auf myHandle verwenden sollte und nie etwas über den zugrunde liegenden Typ übernehmen, so sollten Sie in der Lage sein, die typedef später zu ändern - es sei denn, gibt es "schlampig" Client-Code, der Annahmen macht, sollte es nicht.


Wenn Sie vollständig verstecken wollen, was hinter myHandle ist, ein struct ist Ihre einzige Option in C:

typedef struct myHandle myHandle; 

frobnicate(myHandle *obj); 

und nur in einem privaten Kopf- oder Implementierungsdatei, werden Sie setzen

struct myHandle 
{ 
    char val; 
}; 

Die erste Option ist einfacher, weil innerhalb der Implementierung von frobnicate() können Sie auf Ihren Wert zugreifen, indem Sie einfach *obj verwenden, während die zweite Option obj->val schreiben muss. Was Sie mit der zweiten Version gewinnen, ist, dass Sie Force Client-Code korrekt geschrieben werden.

In Bezug auf die resultierende ausführbare Datei sind beide Versionen gleichwertig.

+1

Ich werde für die zweite Version entscheiden. Das wird mit dem Rest meines Codes konsistenter sein, und ich bevorzuge es immer, meine Absicht durchzusetzen, anstatt sie nur anzugeben. Und irgendwie ist das Hinzufügen des syntaktischen Overheads von 'obj-> val' nicht viel, da es dort nicht viel Code geben wird, erwarten Sie für den Dereferenzierungsteil. Danke für diese Antwort, das hat mir geholfen, mich zu entscheiden! – VannTen

+0

@VannTen die Dereferenz wird immer mit undurchsichtigen Handles/Zeigern benötigt, und mit 'obj-> val' findet der Compiler nur einen Offset von' 0', der dem Zeiger hinzugefügt wird, was natürlich eliminiert wird habe keinen zusätzlichen Aufwand in der Binärdatei. Ich persönlich bevorzuge es, die korrekte Verwendung meiner Schnittstellen zu erzwingen (so weit dies möglich ist), aber es ist Geschmackssache;) Gute Frage, übrigens bin ich früher auf dieselbe Designentscheidung gestoßen. –

Verwandte Themen