2014-01-21 6 views
7

Ich möchte etwas tun, das unmöglich scheint.Ist es möglich, einen Teil eines Standard-Headers (in C) zu verstecken?

Ich möchte 3 Dateien schreiben: main.c, foo.h, foo.c.
Die Idee ist, eine Struktur in foo.h oder foo.c so zu definieren, dass seine Mitglieder in main.c sichtbar sind. Eines der Strukturelemente hat den Typ FILE, wie im Standardkopf <stdio.h> definiert. Aber die Funktionen und Makros von <stdio.h> müssen in der Datei main.c nicht sichtbar bleiben.

Die Lösung müsste dem Standard C (C99 und/oder C11) entsprechen und portabel sein. Ist das möglich?

Der Header foo.h wird in beiden, main.c und foo.c #include.
Der Standard-Header <stdio.h> ist # nur in foo.c enthalten, aber nicht in main.c.

Ich möchte ein struct erklären, wie folgt:

struct myfile_s { 
    FILE *F; 
    char *filename; 
    char buff[100]; 
} myfile; 

Für das, was folgt, nur das Mitglied FILE *F wichtig ist.
Die Struktur myfile wird durch Funktionen initialisiert und geändert, die in foo.c erscheinen.
Die Absicht ist, Dateioperationen auf myfile durch extern Funktionen in foo.h erklärt zu tun, was wiederum in foo.c definiert werden.

Die Dateioperationen beinhalten Standardfunktionen von <stdio.h>, aber diese Funktionen müssen in der Datei main.c versteckt werden. Allerdings möchte ich direkt von main.c auf die Mitglieder von myfile zugreifen. Dies würde bedeuten, dass die Definition von struct myfile_s in foo.h getan werden muss (das heißt, es kann nicht mit dem Trick der Verwendung unvollständiger struct-Deklarationen wie struct myfile_s ; "verzögert" werden).

Kurz gesagt, ich möchte, dass die Art FILE und/oder foo.h, aber der Rest von <stdio.h> Erklärungen in main.c sichtbar sein immer für sie versteckt.

Eine weitere Einschränkung: die Idee, die Definition von FILE von <stdio.h> "zur Hand" direkt zu kopieren, wäre nicht wünschenswert, weil der Code portabel sein müsste.

Mein erster Versuch war die struct myfile Hidding durch Schreiben in foo.c.
Der Code war:

foo.h

struct myfile_s; 

struct myfile_s myfile; 

extern void startfile(struct myfile *f); 

foo.c

#include <stdio.h> 
#include "foo.h" 

struct myfile_s { 
    FILE *F; 
    char *filename; 
    char buff[100]; 
} myfile; 

void startfile(struct myfile *f) 
{ 
    // Do some stuff... 
} 

main.c

#include "foo.h" 

int main(void) 
{ 
    myfile.F = NULL; // This kind of access bring error, but I want to do it anyway!! 
    startfile(&myfile); 
    return 0; 
} 

Die verzögerte struct myfile_s Erklärung vermeidet die Notwendigkeit <stdio.h> in foo.h, enthält, so dass der Kopf funktioniert gut, aber der Strukturtyp bleibt unvollständig, so dass der Zugang zu myfile.F nicht in main.c erfolgen.

So: Wie kann ich auf myfile.F zugreifen?

habe ich versucht, eine andere Art und Weise, dass, natürlich, Fehler gibt zu:

foo.h

struct myfile_s { 
    FILE *F; 
    char *filename; 
    char buff[100]; 
} myfile; 

extern void startfile(struct myfile *f); 

foo.c

#include <stdio.h> 
#include "foo.h" 

void startfile(struct myfile *f) 
{ 
    // Do some stuff... 
} 
+0

wäre es nicht genug mit zwei verschiedenen Headern zu arbeiten? eine interne Headerdatei und eine externe? Das externe Element kennt nur den void pointer (oder in Ihrem Fall den FILE pointer Teil der Struktur) und intern wertet man diese void pointer auf die Typen aus, so dass derjenige mit der internen headerdatei die Teile kennt, die intern bleiben sollen und die externe header jsut zeigt was du ausgeben willst. – dhein

+0

Haben Sie versucht, einschließlich '' in 'foo.h', d. H. Wo Sie Ihre Struktur definieren ... Ich bevorzuge, es in der Kopfzeile zu deklarieren –

+0

Was nicht mit dem zweiten Ansatz funktioniert? Es sieht meistens auf dem richtigen Weg aus. –

Antwort

7
struct myfile_s { 
    void *pPrivateThings; // This could be the FILE* or another private structure 
    char *filename; 
    char buff[100]; 
} myfile; 

I würde ein anderes pri zuweisen vate Struktur zur Erstellung:

struct myprivatefile_s { 
    FILE *F; 
    // You could add other fields here that are not public 
} myprivatefile; 

myprivatefile *privateThings = malloc(sizeof(myprivatefile)); 
myfile.pPrivateThings = privateThings; 
privateThings->F = fopen(); 

diese Weise können Sie über das Hinzufügen Dinge halten können, die erforderlich sind, nicht sichtbar zu sein (d privat) nach Herzenslust.

+1

Sieht aus wie die pimpl C++ Idiom. Nur würde ich hinzufügen, dass Sie einfach "struct myprivatefile_s;" deklarieren können, ohne es im Header "public" zu definieren, und verwenden Sie den Typ im Zeiger anstelle von 'void *'. – Medinoc

+0

Sie verwenden 'myfile' als" type ", aber es ist eine Variable vom Typ' struct myfile_s'. Dies ist jedoch ein geringfügiger Fehler. Ich habe versucht, void * Zeiger noch zu verwenden, die Zugriff auf myfile.F bringt, aber jetzt ist das Problem, dass der "tatsächliche" Typ 'FILE' nicht" rein "ist (es ist nicht der echte). Sie haben jedoch eine gute Antwort gegeben, basierend auf der Art und Weise, wie ich die Frage ausgeführt habe. Es ist nicht das, wonach ich suche, aber deine Antwort ist meine Lieblingsfrage, da du mir verschiedene Ideen gegeben hast. – pablo1977

+0

Danke für den Hinweis auf den Fehler. Habe es korrigiert und gezeigt, wie man den Dateizeiger damit benutzt. – noelicus

6

Das ist alles unnötig kompliziert, oder?

Es sieht so aus, als ob Sie nicht wirklich wissen, was Sie wollen. Warum möchten Sie eine einzige Instanz von myfile in foo.h haben? Warum möchten Sie myfile.F explizit in main setzen? Warum schreiben Sie keine Funktion wie myfile_init dafür in foo.c, die vollen Zugriff hat?

ich eine typedef von einem undurchsichtigen Struktur tun würde das Zeug und implementieren Konstruktor und Zugriffsfunktionen in foo.h in foo.h definieren und dann eine Instanz von myfile in main.c erstellen:

foo.h

typedef struct Myfile Myfile; 

Myfile *myfile_open(const char *filename); 
myfile_process(Myfile *f, ...); 
int myfile_close(Myfile *f); 

foo.c

#include <stdio.h> 

struct Myfile { 
    FILE *f; 
    ... 
}; 

// implement myfile_xxx functions 

main.c

#include "foo.h" 

int main() 
{ 
    Myfile *f = myfile_open("rhubarb.txt"); 

    if (f == NULL) exit(1); 
    myfile_process(f, ...); 
    myfile_close(f); 

    return 0; 
} 

Keine Notwendigkeit, teilweise auch andere Header. Durch Verschieben der Initialisierung auf myfile_open wird alles sauber in foo.c gekapselt. Das Hauptprogramm sieht nur Handles. Ganz wie der Standard FILE * Griffe, wirklich.

Verwandte Themen