Ich habe viele Programme gesehen, die aus Strukturen wie der folgenden bestehen
typedef struct
{
int i;
char k;
} elem;
elem user;
Warum wird sie so oft benötigt? Gibt es einen bestimmten Grund oder ein bestimmtes Gebiet?
Ich habe viele Programme gesehen, die aus Strukturen wie der folgenden bestehen
typedef struct
{
int i;
char k;
} elem;
elem user;
Warum wird sie so oft benötigt? Gibt es einen bestimmten Grund oder ein bestimmtes Gebiet?
Wie Greg Hewgill sagte, bedeutet der Typedef, dass Sie nicht mehr schreiben müssen struct
überall auf der Welt. Das spart nicht nur Tastenanschläge, sondern kann den Code auch sauberer machen, da es ein klein wenig mehr Abstraktion bietet.
Dinge wie
typedef struct {
int x, y;
} Point;
Point point_new(int x, int y)
{
Point a;
a.x = x;
a.y = y;
return a;
}
wird sauberer, wenn man nicht überall das Schlüsselwort "struct" sehen muss, es sieht eher so aus, als gäbe es wirklich einen Typ namens "Point" in Ihrer Sprache. Was, nach dem typedef
ist der Fall, denke ich.
Beachten Sie auch, dass in Ihrem Beispiel (und auch in meinem) die Nennung der struct
selbst, die Benennung ist auch dann nützlich, wenn Sie einen undurchsichtigen Typ bereitstellen möchten. Dann hätten Sie zum Beispiel Code wie diesen in der Kopfzeile:
typedef struct Point Point;
Point * point_new(int x, int y);
und stellen dann die struct
Definition in der Implementierungsdatei:
struct Point
{
int x, y;
};
Point * point_new(int x, int y)
{
Point *p;
if((p = malloc(sizeof *p)) != NULL)
{
p->x = x;
p->y = y;
}
return p;
}
Im letzteren Fall können Sie den Punkt nicht als Wert zurückgeben, da seine Definition für Benutzer der Header-Datei verborgen ist. Dies ist eine Technik, die häufig in GTK+ zum Beispiel.
UPDATE Beachten Sie, dass es auch hoch angesehene C-Projekte gibt, bei denen diese Verwendung von typedef
zu verstecken struct
als eine schlechte Idee angesehen wird, ist der Linux-Kernel wahrscheinlich das bekannteste Projekt dieser Art. Siehe Kapitel 5 von Das Dokument Linux Kernel CodingStyle für Linus' wütende Worte :) Ich will damit sagen, dass das "sollte" in der Frage vielleicht doch nicht in Stein gemeißelt ist.
Es ist erstaunlich, wie viele Leute das falsch verstehen. BITTE keine typedef structs in C, es verschmutzt unnötig den globalen Namespace, der in großen C-Programmen typischerweise schon sehr verschmutzt ist.
Außerdem sind typisierte Strukturen ohne Tag-Namen eine Hauptursache für die unnötige Auferlegung von Ordnungsbeziehungen zwischen Header-Dateien.
Bedenken Sie:
#ifndef FOO_H
#define FOO_H 1
#define FOO_DEF (0xDEADBABE)
struct bar; /* forward declaration, defined in bar.h*/
struct foo {
struct bar *bar;
};
#endif
Mit einer solchen Definition, die keine Typedefs verwendet, ist es für eine Compiland-Unit möglich, foo.h einzubinden, um an die FOO_DEF
Definition. Wenn es nicht versucht, das 'bar'-Mitglied der foo
struct, dann ist es nicht notwendig, die Datei "bar.h" einzubinden.
Da die Namespaces zwischen den Tag-Namen und den Member-Namen unterschiedlich sind, ist es auch möglich, sehr lesbaren Code zu schreiben, wie z.B.:
struct foo *foo;
printf("foo->bar = %p", foo->bar);
Da die Namensräume getrennt sind, gibt es keinen Konflikt bei der Benennung von Variablen, die mit dem Namen ihres Struktur-Tags übereinstimmen.
Wenn ich Ihren Code pflegen muss, werde ich Ihre typisierten Strukturen entfernen.
Aus einem alten Artikel von Dan Saks ( http://www.ddj.com/cpp/184403396?pgno=3 ):
Die Regeln der Sprache C für die Benennung von structs sind ein wenig exzentrisch, aber sie sind ziemlich harmlos. Wenn jedoch auf Klassen in C++ ausgedehnt werden, öffnen dieselben Regeln kleine Risse, durch die Bugs krabbeln.
In C wird der Name s, der in
struct s { ... };
ist eine Markierung. Ein Tag-Name ist kein Typ name. In Anbetracht der obigen Definition, Deklarationen wie
s x; /* error in C */ s *p; /* error in C */
sind Fehler in C. Sie müssen sie schreiben als
struct s x; /* OK */ struct s *p; /* OK */
Die Namen von Unions und Aufzählungen sind ebenfalls Tags und keine Typen.
In C unterscheiden sich die Tags von allen anderen Namen (für Funktionen, Typen, Variablen und Aufzählungskonstanten). C-Compiler verwalten Tags in einer Symbol Tabelle, die konzeptionell, wenn auch nicht physisch getrennt von der Tabelle die alle anderen Namen enthält. Daher ist es ist es möglich, dass ein C-Programm einen Tag und einen anderen Namen mit der gleichen Schreibweise im gleichen Bereich haben. Zum Beispiel,
struct s s;
ist eine gültige Erklärung, die Variable s vom Typ struct s deklariert. Es mag keine gute Praxis sein, aber C-Compiler müssen es akzeptieren. Ich habe noch nie eine Begründung gesehen, warum C so entworfen wurde Weise entworfen wurde. Ich habe immer gedacht, es sei ein Fehler, aber so ist es.
Viele Programmierer (einschließlich Ihrer wirklich) ziehen es vor, Strukturnamen als als Typnamen zu betrachten, daher definieren sie einen Alias für das Tag unter Verwendung eines Typedefs. Für Beispiel: Definition von
struct s { ... }; typedef struct s S;
können Sie S anstelle von struct s verwenden, wie in
S x; S *p;
Ein Programm kann S nicht als Name von eines Typs und einer Variablen (oder Funktion oder Aufzählungskonstante) verwenden:
S S; // error
Das ist gut.
Der Tag-Name in einer Struktur, Union oder enum-Definition ist optional. Viele Programmierer falten die struct-Definition in das Typedef ein und verzichten auf das Tag gänzlich verzichten, wie in:
typedef struct { ... } S;
Der verlinkte Artikel hat auch eine Diskussion darüber, wie die C++-Verhalten von nicht erfordern eine typedef
kann zu subtilen Problemen beim Verbergen von Namen führen. Um diese Probleme zu vermeiden, ist es eine gute Idee typedef
Ihre Klassen und Strukturen auch in C++, auch wenn es auf den ersten Blick unnötig erscheint. In C++, mit der typedef
wird das Verstecken des Namens zu einem Fehler, auf den Sie der Compiler hinweist, und nicht zu einer versteckten Quelle potenzieller Probleme.
Ein weiterer guter Grund, enums und structs immer zu typisieren, ergibt sich aus diesem Problem:
enum EnumDef
{
FIRST_ITEM,
SECOND_ITEM
};
struct StructDef
{
enum EnuumDef MyEnum;
unsigned int MyVar;
} MyStruct;
Beachten Sie den Tippfehler in EnumDef in der Struktur (Enu u mDef)? Dies kompiliert ohne Fehler (oder Warnung) und ist (abhängig von der wörtlichen Interpretation des C-Standards) korrekt. Das Problem ist, dass ich gerade eine neue (leere) Aufzählungsdefinition innerhalb meiner Struktur erstellt habe. Ich verwende nicht (wie beabsichtigt) die vorherige Definition EnumDef.
Mit einem typdef hätten ähnliche Tippfehler zu einem Compilerfehler wegen der Verwendung eines unbekannten Typs geführt:
typedef
{
FIRST_ITEM,
SECOND_ITEM
} EnumDef;
typedef struct
{
EnuumDef MyEnum; /* compiler error (unknown type) */
unsigned int MyVar;
} StructDef;
StrructDef MyStruct; /* compiler error (unknown type) */
Ich würde dafür plädieren, Strukturen und Aufzählungen IMMER zu typisieren.
Nicht nur, um Tipparbeit zu sparen (kein Wortspiel beabsichtigt ;)), sondern weil es sicherer ist.
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.