Wenn ich eine source.c-Datei mit einer Struktur habe:
struct a {
int i;
struct b {
int j;
}
};
Wie kann diese Struktur in einer anderen Datei (z func.c
)?
Sollte ich eine neue Header-Datei erstellen, deklariere die Struktur dort und füge diesen Header hinzu func.c
?
Oder sollte ich die gesamte Struktur in einer Header-Datei definieren und diese in beide aufnehmen source.c
und func.c
? Wie kann die Struktur deklariert werden extern
in beiden Dateien?
Sollte ich typedef
es? Wenn das so ist, wie?
wenn diese Struktur von einer anderen Datei func.c verwendet werden soll, wie geht das?
Wenn ein Typ in einer Datei verwendet wird (dh in der Datei func.c), muss er sichtbar sein. Der schlechteste Weg, dies zu tun, ist das Kopieren und Einfügen in jede benötigte Quelldatei.
Der richtige Weg besteht darin, es in eine Header-Datei zu packen und diese Header-Datei bei Bedarf einzuschließen.
Sollen wir eine neue Header-Datei öffnen und die Struktur dort deklarieren und diesen Header in die func.c aufnehmen?
Dies ist die Lösung, die ich mehr mag, weil sie den Code sehr modular macht. Ich würde Ihre Struktur wie folgt codieren:
#ifndef SOME_HEADER_GUARD_WITH_UNIQUE_NAME
#define SOME_HEADER_GUARD_WITH_UNIQUE_NAME
struct a
{
int i;
struct b
{
int j;
}
};
#endif
Ich würde Funktionen, die diese Struktur verwenden, in denselben Header einfügen (die Funktion, die “semantisch” Teil ihrer “Schnittstelle” ist).
Und normalerweise könnte ich die Datei nach dem Strukturnamen benennen und diesen Namen erneut verwenden, um die Header Guards-Definitionen auszuwählen.
Wenn Sie eine Funktion mit einem Zeiger auf die Struktur deklarieren müssen, benötigen Sie nicht die vollständige Strukturdefinition. Eine einfache Forward-Deklaration wie:
struct a ;
Wird ausreichen, und es verringert die Kopplung.
oder können wir die Gesamtstruktur in der Header-Datei definieren und diese sowohl in source.c als auch in func.c einfügen?
Dies ist ein anderer Weg, etwas einfacher, aber weniger modular: Code, der nur Ihre Struktur benötigt, um zu funktionieren, müsste immer noch alle Typen enthalten.
In C++ könnte dies zu interessanten Komplikationen führen, aber das gehört nicht zum Thema (kein C++-Tag), daher gehe ich nicht näher darauf ein.
dann wie man diese Struktur in beiden Dateien als extern deklariert. ?
Ich verstehe den Sinn vielleicht nicht, aber Greg Hewgill hat eine sehr gute Antwort in seinem Beitrag Wie deklariere ich eine Struktur in einem Header, der von mehreren Dateien in c verwendet werden soll?.
Sollen wir es dann wie eingeben?
- Wenn Sie C++ verwenden, tun Sie dies nicht.
- Wenn Sie C verwenden, sollten Sie.
Der Grund dafür ist, dass die Verwaltung von C-Strukturen mühsam sein kann: Sie müssen das Schlüsselwort struct überall dort deklarieren, wo es verwendet wird:
struct MyStruct ; /* Forward declaration */
struct MyStruct
{
/* etc. */
} ;
void doSomething(struct MyStruct * p) /* parameter */
{
struct MyStruct a ; /* variable */
/* etc */
}
Während ein Typedef es Ihnen ermöglicht, es ohne das Schlüsselwort struct zu schreiben.
struct MyStructTag ; /* Forward declaration */
typedef struct MyStructTag
{
/* etc. */
} MyStruct ;
void doSomething(MyStruct * p) /* parameter */
{
MyStruct a ; /* variable */
/* etc */
}
es ist wichtig Sie behalten immer noch einen Namen für die Struktur. Schreiben:
typedef struct
{
/* etc. */
} MyStruct ;
erstellt nur eine anonyme Struktur mit einem typdefinierten Namen, und Sie können ihn nicht vorwärts deklarieren. Halten Sie sich also an das folgende Format:
typedef struct MyStructTag
{
/* etc. */
} MyStruct ;
Daher können Sie MyStruct überall dort verwenden, wo Sie das Hinzufügen des Schlüsselworts struct vermeiden möchten, und MyStructTag trotzdem verwenden, wenn eine Typedef nicht funktioniert (dh Vorwärtsdeklaration).
Bearbeiten:
Korrigierte falsche Annahme über die C99-Strukturdeklaration, wie zu Recht von Jonathan Leffler bemerkt wurde.
Bearbeiten 01.06.2018:
Craig Barnes erinnert uns in seinem Kommentar daran, dass Sie keine separaten Namen für den „tag“-Namen der Struktur und ihren „typedef“-Namen verwenden müssen, wie ich es oben der Übersichtlichkeit halber getan habe.
Tatsächlich könnte der obige Code gut geschrieben werden als:
typedef struct MyStruct
{
/* etc. */
} MyStruct ;
IIRC, das ist eigentlich das, was C++ mit seiner einfacheren Struct-Deklaration hinter den Kulissen macht, um es mit C kompatibel zu halten:
// C++ explicit declaration by the user
struct MyStruct
{
/* etc. */
} ;
// C++ standard then implicitly adds the following line
typedef MyStruct MyStruct;
Zurück zu C, ich habe beide Verwendungen gesehen (getrennte Namen und gleiche Namen), und keine hat Nachteile, die ich kenne, also macht die Verwendung des gleichen Namens das Lesen einfacher, wenn Sie C keine separaten “Namespaces” für Strukturen und andere Symbole verwenden .
Für eine Strukturdefinition, die über mehr als eine Quelldatei hinweg verwendet werden soll, sollten Sie diese unbedingt in eine Header-Datei packen. Fügen Sie dann diese Header-Datei in jede Quelldatei ein, die die Struktur benötigt.
Das extern
Die Deklaration wird nicht für Strukturdefinitionen verwendet, sondern für Variablendeklarationen (d. h. einige Datenwerte mit einem von Ihnen definierten Strukturtyp). Wenn Sie dieselbe Variable in mehr als einer Quelldatei verwenden möchten, deklarieren Sie sie als extern
in einer Header-Datei wie:
extern struct a myAValue;
Dann in eines Quelldatei, definieren Sie die eigentliche Variable:
struct a myAValue;
Wenn Sie dies vergessen oder versehentlich in zwei Quelldateien definieren, werden Sie vom Linker darauf hingewiesen.
Ah:
#ifndef A_H
#define A_H
struct a {
int i;
struct b {
int j;
}
};
#endif
Los geht’s, jetzt müssen Sie nur noch ah in die Dateien einfügen, in denen Sie diese Struktur verwenden möchten.
Beachten Sie, dass die Strukturdefinition kein gültiges C ist. Nach der schließenden Klammer für sollte mindestens ein Semikolon stehen
struct b
aber dann Ihre Struktura
deklariert einen Typ, der nicht verwendet wird (vielleicht sollten Sie einen Mitgliedsnamen definierenk
nach der inneren geschlossenen Klammer und vor dem Semikolon.– Jonathan Leffler
30. September 2014 um 23:57 Uhr