Frage

Ich habe gesehen, viele Programme, bestehend aus Strukturen wie unten

typedef struct 
{
    int i;
    char k;
} elem;

elem user;

Warum ist es notwendig, so oft?Alle spezifischen Grund oder anwendbarer Bereich?

War es hilfreich?

Lösung

Wie Greg Hewgill sagte, die typedef bedeutet, dass Sie nicht mehr struct ganz über den Platz zu schreiben. Das ist nicht nur Tastatureingaben speichert, kann sie auch den Code sauberer machen, da es eine ganz klein wenig mehr Abstraktion bereitstellt.

Stuff wie

typedef struct {
  int x, y;
} Point;

Point point_new(int x, int y)
{
  Point a;
  a.x = x;
  a.y = y;
  return a;
}

Reiniger wird, wenn Sie brauchen, um die „Struktur“ Schlüsselwort nicht zu sehen, alle über den Ort, sieht es eher, als ob es wirklich eine Art „Point“ in Ihrer Sprache genannt wird. Was nach dem typedef, ist der Fall, denke ich.

Beachten Sie auch, dass, während Ihr Beispiel (und mir) weggelassen sich die struct nennen, eigentlich ist es Namensgebung für auch nützlich, wenn Sie eine undurchsichtige Art zur Verfügung stellen möchten. Dann würden Sie Codes wie diese im Header haben, zum Beispiel:

typedef struct Point Point;

Point * point_new(int x, int y);

und geben Sie 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;
}

In diesem letzteren Fall können Sie den Punkt nach Wert nicht zurück, da die Definition von Benutzern der Header-Datei versteckt ist. Dies ist eine Technik weit verbreitet in der GTK + zum Beispiel verwendet wird.

UPDATE Beachten Sie, dass es auch hoch angesehene C Projekte, bei denen diese Verwendung von typedef struct zu verstecken einer schlechten Idee betrachtet wird, ist das Linux-Kernel wahrscheinlich das bekannteste solches Projekt. Siehe Kapitel 5 von Der Linux-Kernel Coding Dokument für Linus' böse Worte. :) Mein Punkt ist, dass die „sollte“ in der Frage vielleicht nicht in Stein gemeißelt ist, nachdem alle.

Andere Tipps

Es ist erstaunlich, wie viele Menschen dies falsch. BITTE typedef nicht structs in C, es verpestet unnötig den globalen Namensraum, die in großen C-Programme bereits verschmutzt typischerweise sehr ist.

Auch typedef'd structs ohne Tag-Namen sind eine der Hauptursachen für unnötige Einführung von Beziehungen zwischen den Header-Dateien zu bestellen.

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 nicht typedefs verwenden, ist es möglich, dass ein compiland Einheit foo.h aufzunehmen an der FOO_DEF Definition zu erhalten. Wenn es nicht versuchen, nicht dereferenzieren das ‚Bar‘ Mitglied der foo struct dann wird es keine Notwendigkeit, die „bar.h“ Datei aufzunehmen.

Da auch die Namensräume unterschiedlich zwischen den Tag-Namen und den Mitgliedsnamen sind, ist es möglich, sehr lesbaren Code zu schreiben, wie zum Beispiel:

struct foo *foo;

printf("foo->bar = %p", foo->bar);

Da die Namensräume getrennt sind, gibt es keinen Konflikt in Variablen gleichzeitig mit ihrer Struktur Tag-Namen zu nennen.

Wenn ich Ihren Code zu erhalten, werde ich Ihre typedef'd structs entfernen.

Von einem alten Artikel von Dan Saks ( http://www.ddj.com/ ? CPP / 184403396 pgno = 3 ):


  

Die Sprache C Regeln für die Benennung   structs sind ein wenig exzentrisch, aber   sie sind ziemlich harmlos. Wenn jedoch   erweitert, um Klassen in C ++, die gleichen   Regeln öffnen kleinen Riss für Bugs   kriechen durch.

     

In C s erscheint der Name in

struct s
    {
    ...
    };
     

ist ein Tag. Ein Tag-Name ist kein Typ   Name. Gegeben über die Definition,   Erklärungen wie

s x;    /* error in C */
s *p;   /* error in C */
     

Fehler in C. Sie müssen sie schreiben   wie

struct s x;     /* OK */
struct s *p;    /* OK */
     

Die Namen der Gewerkschaften und Aufzählungen   auch sind die Tags statt Typen.

     

In C-Tags unterscheiden sich von allen anderen   Namen (für Funktionen, Typen,   Variablen und Enumerationskonstanten).   C-Compiler pflegen Tags in einem Symbol   Tabelle, die vom Konzept her, wenn nicht ist   physisch getrennt von dem Tisch   dass hält alle anderen Namen. Also es   Programm ist möglich, dass ein C zu haben   sowohl einen Tag und ein anderer Name mit   die gleiche Schreibweise im gleichen Umfang.   Zum Beispiel:

struct s s;
     

ist eine gültige Erklärung, die erklärt,   Variable s vom Typ struct s. Es kann   seine nicht gute Praxis, aber C-Compiler   muss es akzeptieren. Ich habe noch nie gesehen ein   Gründe dafür, warum C dies wurde entwickelt,   Weg. Ich habe immer gedacht, es war ein   Fehler, aber da ist es.

     

Viele Programmierer (einschließlich Ihrer   wirklich) lieber von struct Namen denken   als Typennamen, so definieren sie einen Alias   für den Tag eines typedef. Zum   Beispiel definieren

struct s
    {
    ...
    };
typedef struct s S;
     

können Sie verwenden S anstelle von struct s,   wie in

S x;
S *p;
     

Ein Programm kann nicht als Name verwendet S von   sowohl ein Typ und eine Variable (oder   Funktion oder Enumerationskonstante):

S S;    // error
     

Das ist gut.

     

Der Tag-Name in einer Struktur, Vereinigung oder   Enum-Definition ist optional. Viele   Programmierer falten Sie die Struktur Definition   in die typedef und verzichten auf die   Tag zusammen, wie in:

typedef struct
    {
    ...
    } S;

Der verlinkte Artikel hat auch eine Diskussion darüber, wie die C ++ Verhalten nicht typedef requireing subtile Namen verstecken Probleme verursachen kann. Um diese Probleme zu vermeiden, ist es eine gute Idee, um Ihre Klassen und Strukturen in C ++ typedef auch, obwohl auf den ersten Blick zu sein unnötig erscheint. In C ++, mit dem typedef Versteck der Name ein Fehler geworden, dass der Compiler Sie eher als eine versteckte Quelle von möglichen Problemen erzählt.

ein typedef Verwendung vermeidet jedes Mal, wenn Sie eine Variable dieses Typs deklarieren struct schreiben:

struct elem
{
 int i;
 char k;
};
elem user; // compile error!
struct elem user; // this is correct

Ein weiterer guter Grund, immer typedef Aufzählungen und structs Ergebnisse dieses Problem:

enum EnumDef
{
  FIRST_ITEM,
  SECOND_ITEM
};

struct StructDef
{
  enum EnuumDef MyEnum;
  unsigned int MyVar;
} MyStruct;

Beachten Sie die Tippfehler in EnumDef in der Struktur (Enu u mDef)? Dies kompiliert ohne Fehler (oder Warnung) und ist (abhängig von der wörtlichen Auslegung des C Standard) korrekt. Das Problem ist, dass ich gerade eine neue (leere) Aufzählung Definition in meiner Struktur erstellt. Ich bin nicht (wie beabsichtigt) die vorherige Definition EnumDef verwendet wird.

Mit einer typdef ähnlichen Art von Fehlern in einem Compiler-Fehler ergeben hätte eine unbekannte Art für die Verwendung:

typedef 
{
  FIRST_ITEM,
  SECOND_ITEM
} EnumDef;

typedef struct
{
  EnuumDef MyEnum; /* compiler error (unknown type) */
  unsigned int MyVar;
} StructDef;
StrructDef MyStruct; /* compiler error (unknown type) */

würde ich befürworten IMMER structs und Aufzählungen typedef'ing.

Nicht nur Tipparbeit zu sparen (kein Wortspiel beabsichtigt;).), Sondern weil es sicherer ist

Linux-Kernel Codierstil Kapitel 5 große Vor-und Nachteile gibt (vor allem Nachteile) von mit typedef.

  

Bitte verwenden Sie keine Dinge wie "vps_t".

     

Es ist ein Fehler für Strukturen zu verwenden typedef und Zeiger. Wenn Sie sehen, ein

vps_t a;
     

in der Quelle, was es bedeutet?

     

Im Gegensatz dazu, wenn es sagt,

struct virtual_container *a;
     

Sie können tatsächlich sagen, was "a" ist.

     

Viele Leute denken, dass typedefs „Hilfe Lesbarkeit“. Nicht so. Sie sind nützlich, nur für:

     

(a) völlig undurchsichtige Objekte (wo die typedef aktiv verwendet wird verbergen , was das Objekt ist).

     

. Beispiel: „pte_t“ usw. undurchsichtige Objekte, dass Sie nur den Zugriff, die richtigen Zugriffsfunktionen mit

     

Hinweis! Undurchsichtigkeit und „Accessorfunktionen“ sind an sich nicht gut. Der Grund, warum wir sie für Dinge wie pte_t usw. ist, dass es wirklich absolut Null portably zugängliche Informationen geben.

     

(b) Klar Integer-Typen, wobei die Abstraktion hilft Verwirrung vermeiden, ob es "int" oder "lang" ist.

     

U8 / U16 / U32 sind völlig in Ordnung typedefs, obwohl sie in der Kategorie passen (d) besser als hier.

     

Hinweis! Auch hier - es muss ein Grund für diese sein. Wenn etwas „unsigned long“ ist, dann gibt es keinen Grund zu tun

typedef unsigned long myflags_t;
     

aber wenn es ein klarer Grund dafür, warum es unter bestimmten Umständen könnte ein „unsigned int“ und unter anderen Konfigurationen sein könnte „unsigned long“ sein, dann mit allen Mitteln voran gehen und eine typedef verwenden.

     

(c), wenn Sie spärlich verwenden, um buchstäblich zu erstellen neue Typ für Typ-Überprüfung.

     

(d) Neue Typen, die auf Standard-Typen C99 identisch sind, in bestimmten Ausnahmefällen.

     

Auch wenn es nur eine kurze Zeit für die Augen und das Gehirn zu den Standardtypen wie ‚uint32_t‘ zu gewöhnen nehmen würde, widersprechen einige Leute ihre Verwendung sowieso.

     

Daher ist die Linux-spezifischen ‚U8 / U16 / U32 / U64‘ Typen und deren unterzeichnet Äquivalente, die auf Standardtypen identisch sind, sind zulässig -. Obwohl sie in neuem Code der eigenen ist nicht obligatorisch

     

Wenn die Code Bearbeitung vorhandener, die bereits verwendet den einen oder anderen Satz von Typen, sollten Sie in diesem Code zu den bestehenden Möglichkeiten entsprechen.

     

(e) Art sicher für den Einsatz in User-Space.

     

In bestimmten Strukturen, die auf Anwenderseite sichtbar sind, können wir nicht C99 Typen erfordern und die obige Form ‚u32‘ nicht verwenden können. So verwenden wir __u32 und ähnliche Arten in allen Strukturen, die mit dem Anwender gemeinsam genutzt werden.

     

Vielleicht gibt es andere Fälle auch, aber die Regel sollte grundsätzlich sein, NIEMALS einen typedef zu verwenden, wenn Sie eindeutig eine dieser Regeln entsprechen können.

     

Im Allgemeinen wird ein Zeiger oder eine Struktur, die Elemente hat, die vernünftigerweise direkt zugegriffen werden sollte nie ein typedef sein.

Es stellt sich heraus, dass es vor-und Nachteile.Eine nützliche Quelle der Informationen ist die bahnbrechenden Buch "Expert C Programming" (Kapitel 3).Kurz, in C haben Sie mehrere namespaces: tags, Typen -, member-Namen und Identifikatoren. typedef stellt einen alias für eine Typ-und findet es in der tag-namespace.Nämlich,

typedef struct Tag{
...members...
}Type;

definiert zwei Dinge.Ein Tag in der tag-namespace und ein Typ in den Typ namespace.So können Sie beides tun Type myType und struct Tag myTagType.Erklärungen wie struct Type myType oder Tag myTagType sind illegal.Darüber hinaus, In einer Erklärung wie diese:

typedef Type *Type_ptr;

wir definieren einen Zeiger auf unsere Art.Also, wenn wir erklären:

Type_ptr var1, var2;
struct Tag *myTagType1, myTagType2;

dann var1,var2 und myTagType1 Zeiger auf Typ, aber myTagType2 nicht.

In dem oben genannten Buch, es wird erwähnt, dass typedefing Strukturen sind nicht sehr nützlich, es speichert nur die Programmierer zu schreiben die Wort-Struktur.Allerdings habe ich einen Einspruch-wie viele andere C-Programmierer.Obwohl es manchmal dreht sich zu verschleiern einige Namen (, dass ist, warum es ist nicht ratsam, in großen code-Basen, wie den kernel), wenn Sie wollen zur Umsetzung Polymorphismus in C hilft viel schauen Sie hier für details.Beispiel:

typedef struct MyWriter_t{
    MyPipe super;
    MyQueue relative;
    uint32_t flags;
...
}MyWriter;

können Sie tun:

void my_writer_func(MyPipe *s)
{
    MyWriter *self = (MyWriter *) s;
    uint32_t myFlags = self->flags;
...
}

So können Sie auf einen äußeren Mitglied (flags), die von der inneren Struktur (MyPipe) durch Gießen.Für mich ist es weniger verwirrend zu wirken, die ganze Art, als das zu tun (struct MyWriter_ *) s; jedes mal, wenn Sie ausführen möchten, diese Funktionalität.In diesen Fällen kurze Referenzierung ist eine große Sache, besonders wenn Sie stark beschäftigen die Technik in Ihrem code.

Schließlich der Letzte Aspekt mit typedefed-Arten ist die Unfähigkeit, Sie zu verlängern, im Gegensatz zu Makros.Wenn Sie beispielsweise:

#define X char[10] or
typedef char Y[10]

Sie können dann erklären

unsigned X x; but not
unsigned Y y;

Wir nicht wirklich wichtig, für diese Strukturen, weil es gilt nicht für die speicherbezeichner (volatile und const).

Ich glaube nicht vorwärts Erklärungen mit typedef auch möglich sind. Die Verwendung von struct, enum, und Vereinigung ermöglicht Forwarding Erklärungen, wenn Abhängigkeiten (kennen) ist bidirektional.

Stil: Die Verwendung von typedef in C ++ macht ziemlich viel Sinn. Es kann fast notwendig sein, wenn mit Vorlagen zu tun, die mehrere und / oder variablen Parameter erfordern. Die typedef hilft die Namensgebung gerade zu halten.

Nicht so in der C-Programmiersprache. Die Verwendung von typedef meisten dient oft keinen Zweck, sondern die Datenstruktur Nutzung zu verschleiern. Da nur {struct (6), ENUM (4), Vereinigung (5)} Anzahl der Tastenanschläge verwendet werden, einen Datentyp zu erklären, gibt es fast keine Verwendung für das Aliasing der Struktur. Ist das Datum, die eine Vereinigung oder eine Struktur geben? die einfache Nicht-typdefed Erklärung verwenden, können Sie sofort wissen, welche Art es ist.

Beachten Sie, wie Linux mit strikter Vermeidung dieses Aliasing Unsinn geschrieben wird typedef bringt. Das Ergebnis ist ein minimalistischer und sauberer Stil.

Lassen Sie uns mit den Grundlagen beginnen und uns auf den Weg arbeiten.

Hier ist ein Beispiel für Strukturdefinition:

struct point
  {
    int x, y;
  };

Hier wird der Name point optional.

Eine Struktur kann während seiner Definition oder nach deklariert werden.

bei der Definition Deklarieren

struct point
  {
    int x, y;
  } first_point, second_point;

Deklarieren nach Definition

struct point
  {
    int x, y;
  };
struct point first_point, second_point;

Nun, beachten Sie sorgfältig den letzten Fall oben; Sie müssen struct point schreiben Strukturen dieser Art zu erklären, wenn Sie diese Art zu einem späteren Zeitpunkt in Ihrem Code erstellen entscheiden.

Geben Sie typedef. Wenn Sie beabsichtigen, neue Struktur zu schaffen (Struktur ist ein benutzerdefinierter Daten-Typ) zu einem späteren Zeitpunkt in Ihrem Programm des gleichen Bauplan verwenden, typedef während seiner Definition verwenden könnte eine gute Idee sein, da Sie etwas Tipp vorwärts bewegt speichern.

typedef struct point
  {
    int x, y;
  } Points;

Points first_point, second_point;

Ein Wort der Vorsicht, während der benutzerdefinierte Typ

Namensgebung

Nichts hindert Sie daran, _t Suffix am Ende des benutzerdefinierten Typnamen aber POSIX-Standard behält sich die Verwendung von Suffix _t zu bezeichnen Standardbibliothek Typnamen verwendet wird.

der Name, den Sie (optional), um die Struktur geben die Tag-Namen genannt und, wie erwähnt, ist kein Typ für sich. Um auf die Art zu erhalten erfordert die Struktur Präfix.

GTK + beiseite, ich bin nicht sicher, dass der Tag-Name etwas verwendet wird, wie so häufig als typedef auf den Struktur-Typen, so in C ++, die erkannt werden, und Sie können das Schlüsselwort struct wegzulassen und die tagname als Typname verwenden:


    struct MyStruct
    {
      int i;
    };

    // The following is legal in C++:
    MyStruct obj;
    obj.i = 7;

typedef wird kein co-abhängige Satz von Datenstrukturen zur Verfügung stellen. Das kann man nicht mit typdef tun:

struct bar;
struct foo;

struct foo {
    struct bar *b;
};

struct bar {
    struct foo *f;
};

Natürlich kann man immer hinzufügen:

typedef struct foo foo_t;
typedef struct bar bar_t;

Was genau ist der Punkt, der das?

A> ein typdef Hilfsmittel im Sinne und Dokumentation eines Programms, indem Schaffung sinnvoller Synonyme für Datentypen . Darüber hinaus helfen sie ein Programm gegen Portabilitätsprobleme (K & R, pg147, C prog lang) parametriert werden.

B> definiert eine Struktur mit einer Art . Structs ermöglicht eine bequeme Gruppierung einer Sammlung von Vars zur Vereinfachung der Handhabung (K & R, pg127, C prog lang.) Als eine einzige Einheit

C> typedef'ing eine Struktur ist in einer oben erläutert.

D> Für mich structs sind benutzerdefinierte Typen oder Container oder Sammlungen oder Namespaces oder komplexe Typen, während ein typdef nur ein Mittel ist mehr Spitznamen zu erstellen.

Es stellte sich heraus in C99 typedef erforderlich ist. Es ist veraltet, aber eine Menge von Werkzeugen (ala HackRank) verwendet c99 als reine C-Implementierung. Und typedef ist erforderlich.

Ich sage nicht, sollten sie ändern (vielleicht zwei C-Optionen haben), wenn die Anforderung geändert, würden die von uns beschlagen für Interviews auf der Website SOL sein.

In ‚C‘ Programmiersprache das Schlüsselwort ‚typedef‘ wird verwendet, um einen neuen Namen für ein Objekt (struct, array, function..enum Typ) zu erklären. Zum Beispiel werde ich ein ‚struct-s‘ verwenden. In ‚C‘ erklären wir oft einen ‚struct‘ außerhalb der ‚main‘ Funktion. Zum Beispiel:

struct complex{ int real_part, img_part }COMPLEX;

main(){

 struct KOMPLEKS number; // number type is now a struct type
 number.real_part = 3;
 number.img_part = -1;
 printf("Number: %d.%d i \n",number.real_part, number.img_part);

}

Jedes Mal, wenn ich entscheiden, einen Strukturtyp verwenden, ich muss dieses Schlüsselwort ‚Struktur‚etwas‘‚name‘.‘ Typedef‘wird einfach diese Art umbenennen und ich den neuen Namen in meinem Programm möchte jedes Mal verwenden kann ich. So ist unser Code wird sein:

typedef struct complex{int real_part, img_part; }COMPLEX;
//now COMPLEX is the new name for this structure and if I want to use it without
// a keyword like in the first example 'struct complex number'.

main(){

COMPLEX number; // number is now the same type as in the first example
number.real_part = 1;
number.img)part = 5;
printf("%d %d \n", number.real_part, number.img_part);

}

Wenn Sie einige lokale Objekt haben (struct, Array, wertvoll), die Sie einfach in Ihrem gesamten Programm verwendet wird geben Sie einen Namen ein ‚typedef‘ verwenden.

Bei allen, in C-Sprache, Struktur / Union / Enum ist Makrobefehl durch die Sprache C Präprozessor verarbeitet wird (nicht mit dem Präprozessor Fehler, dass „# include“ und andere behandeln)

so:

struct a
{
   int i;
};

struct b
{
   struct a;
   int i;
   int j;
};

struct b wird als so etwas wie dieses aufgewandt:

struct b
{
    struct a
    {
        int i;
    };
    int i;
    int j;
}

und so, bei der Kompilierung auf Stapel als etwas entwickeln, wie: b: int ai int i int j

das auch, warum es dificult selfreferent structs, C Präprozessor Runde in einem déclaration Schleife zu haben, die nicht beendet werden kann.

typedef Typspezifizierer ist, bedeutet, dass nur verarbeiten C-Compiler und es tun kann, wie er für optimize Assembler-Code Implementierung möge. Es nicht auch Mitglied des Typ par aufwenden dummerweise wie Preprocessor mit structs zu tun, aber komplexen Referenzkonstruktionsalgorithmus verwenden, so Konstruktion wie:

typedef struct a A; //anticipated declaration for member declaration

typedef struct a //Implemented declaration
{
    A* b; // member declaration
}A;

ist permited und voll funktionsfähig. Diese Implementierung geben auch Zugriff auf Typumwandlung und entfernen Sie einige Lausch Effekte, wenn die Ausführung Thread verlassen das Anwendungsfeld der Initialisierung Funktionen compilator.

Dies bedeutet, dass in C typedefs ist in der Nähe wie C ++ Klasse als einsames structs.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top