C: Typedef-Strukturname {…}; VS typedef struct{…} name;

Lesezeit: 11 Minuten

Benutzeravatar von Alek Sobczyk
Alex Sobczyk

Wie der Titel schon sagt, habe ich diesen Code:

    typedef struct Book{
        int id;
        char title[256];
        char summary[2048];
        int numberOfAuthors;
        struct Author *authors;
    };


    typedef struct Author{
        char firstName[56];
        char lastName[56];
    };


    typedef struct Books{
        struct Book *arr;
        int numberOfBooks;
    };

Ich bekomme diese Fehler von gcc:

bookstore.c:8:2: error: unknown type name ‘Author’
bookstore.c:9:1: warning: useless storage class specifier in empty declaration [enabled by default]
bookstore.c:15:1: warning: useless storage class specifier in empty declaration [enabled by default]
bookstore.c:21:2: error: unknown type name ‘Book’
bookstore.c:23:1: warning: useless storage class specifier in empty declaration [enabled by default]

Es treten keine Warnungen und keine Fehler auf, wenn ich die Typedefs wie folgt ändere:

    typedef struct{
        char firstName[56];
        char lastName[56];
    } Author;

Durchgesucht Programmiersprache C, 2. Auflage und ein paar Stunden gegoogelt, kann ich nicht herausfinden, warum die erste Implementierung nicht funktioniert.

  • Beweg den Author Vor Book. Beachten Sie auch, dass Ihre typedefs sind überflüssig

    – SomeWittyBenutzername

    18. Juli 2013 um 9:59 Uhr


  • Wie ist es möglich, dass sich das einfach ändert Author Struktur entfernt sich error:unknown type name ‘Book’ Auch? Bitte sieh dir das mal an hier die deutlich den Unterschied zwischen typdef einer Struktur und dem Definieren einer Struktur erwähnen.

    – Tagesrai

    18. Juli 2013 um 10:16 Uhr

Benutzeravatar von Daniel Goldfarb
Daniel Goldfarb

Hier ist einiges los. Erstens, wie andere gesagt haben, kann die Beschwerde des Compilers über unbekannte Typen darauf zurückzuführen sein, dass Sie die Typen deklarieren müssen, bevor Sie sie verwenden. Wichtiger ist jedoch, die Syntax von 3 Dingen zu verstehen:

  1. Definition des Strukturtyps,
  2. Definition und Deklaration der Strukturvariablen und
  3. Typdef

(Beachten Sie, dass in der Programmiersprache C Definition und Deklaration normalerweise gleichzeitig erfolgen und daher im Wesentlichen gleich sind. Dies ist in vielen anderen Sprachen nicht der Fall. Weitere Einzelheiten finden Sie in der Fußnote unten.)

Beim Definieren einer Struktur kann die Struktur getaggt (benannt) oder ungetaggt sein (wenn sie nicht getaggt ist, muss die Struktur sofort verwendet werden (wird weiter unten erklären, was dies bedeutet)).

struct Name {
   ...
};

Dies definiert einen Typ namens “struct Name”, der dann verwendet werden kann, um eine Strukturvariable/Instanz zu definieren:

struct Name myNameStruct;

Dies definiert eine Variable namens myNameStruct das ist eine Struktur vom Typ struct Name.

Sie können auch eine Struktur definieren und gleichzeitig eine Strukturvariable deklarieren/definieren:

struct Name {
   ...
} myNameStruct;

Wie zuvor definiert dies eine Variable namens myNameStruct das ist eine Instanz des Typs struct NameAber es tut es gleichzeitig, indem es den Typ definiert struct Name.
Der Typ kann dann erneut verwendet werden, um eine andere Variable zu deklarieren und zu definieren:

struct Name myOtherNameStruct;

Jetzt typedef ist nur eine Möglichkeit, einen Typ mit einem bestimmten Namen zu aliasieren:

typedef OldTypeName NewTypeName;

Angesichts der obigen Typdefinition können Sie jederzeit verwenden NewTypeName es ist dasselbe wie mit OldTypeName. In der Programmiersprache C ist dies besonders nützlich bei Strukturen, da es Ihnen die Möglichkeit gibt, das Wort “Struktur” wegzulassen, wenn Sie Variablen dieses Typs deklarieren und definieren und den Namen der Struktur einfach als eigenen Typ zu behandeln (wie wir es in C++ tun). Hier ist ein Beispiel, das zuerst die Struktur definiert und dann die Struktur typdefiniert:

struct Name {
   ...
};

typedef struct Name Name_t;

In obigem OldTypeName steht struct Name und NewTypeName ist Name_t. Um nun also eine Variable vom Typ struct Name zu definieren, anstatt zu schreiben:

struct Name myNameStruct;

Ich kann einfach schreiben:

Name_t myNameStruct;

BEACHTEN SIE AUCH, dass die Typedef mit der Struct-Definition KOMBINIERT WERDEN KANN, und dies ist, was Sie in Ihrem Code tun:

typedef struct {
   ...
} Name_t;

Dies kann auch beim Taggen (Benennen) der Struktur erfolgen. Dies ist nützlich für selbstreferenzielle Strukturen (zum Beispiel Linked-List-Knoten), aber ansonsten überflüssig. Nichtsdestotrotz folgen viele der Praxis, Strukturen immer zu markieren, wie in diesem Beispiel:

typedef struct Name {
   ...
} Name_t;

ACHTUNG: Da Sie in der obigen Syntax mit “typedef” begonnen haben, ist die gesamte Anweisung a typedef -Anweisung, in der OldTypeName zufällig eine Struct-Definition ist. Daher interpretiert der Compiler den Namen kommend nach die rechte geschweifte Klammer } als NewTypeName … es ist NICHT den Variablennamen (wie er in der Syntax ohne typedef wäre, in diesem Fall würden Sie die Struktur definieren und gleichzeitig eine Strukturvariable deklarieren/definieren).

Wenn Sie außerdem typedef angeben, aber Name_t am Ende weglassen, dann haben Sie effektiv eine INCOMPLETE typedef-Anweisung erstelltweil der Compiler alles innerhalb von “struct Name { ... }” als OldTypeName, und Sie geben keinen NewTypeName für die Typedef an. Aus diesem Grund ist der Compiler mit dem von Ihnen geschriebenen Code nicht zufrieden (obwohl die Meldungen des Compilers ziemlich kryptisch sind, da er nicht ganz sicher ist, was Sie falsch gemacht haben).

Nun, wie ich oben erwähnt habe, wenn Sie den Strukturtyp zum Zeitpunkt der Definition nicht taggen (benennen), müssen Sie ihn sofort verwenden, entweder um eine Variable zu definieren:

struct {
   ...
} myNameStruct;  // defines myNameStruct as a variable with this struct
                 // definition, but the struct definition cannot be re-used.

Oder Sie können einen nicht getaggten Strukturtyp innerhalb einer Typedef verwenden:

typedef struct {
   ...
} Name_t;

Diese letzte Syntax ist das, was Sie tatsächlich getan haben, als Sie geschrieben haben:

typedef struct{
   char firstName[56];
   char lastName[56];
} Author;

Und der Compiler war glücklich. HTH.

In Bezug auf den Kommentar / die Frage zum Suffix _t:

Das Suffix _t ist eine Konvention, um Personen, die den Code lesen, anzuzeigen, dass der symbolische Name mit dem _t ein Typname ist (im Gegensatz zu einem Variablennamen). Der Compiler analysiert das _t nicht und ist sich dessen auch nicht bewusst.

Die C89- und insbesondere die C99-Standardbibliotheken definierten viele Typen und entschieden sich dafür, das _t für die Namen dieser Typen zu verwenden. Zum Beispiel definiert der C89-Standard wchar_t, off_t, ptrdiff_t. Der C99-Standard definiert viele zusätzliche Typen, wie z. B. uintptr_t, intmax_t, int8_t, uint_least16_t, uint_fast32_t usw. Aber _t ist nicht reserviert, noch speziell analysiert, noch vom Compiler bemerkt, es ist lediglich eine Konvention, die gut zu befolgen ist wenn Sie neue Typen (über typedef) in C definieren. In C++ verwenden viele Leute die Konvention, Typnamen mit einem Großbuchstaben zu beginnen, zum Beispiel MyNewType ( im Gegensatz zur C-Konvention my_new_type_t ). HTH


Fußnote über die Unterschiede zw erklären und definieren: Zunächst ein besonderer Dank an @CJM für die Vorschläge zur Klärung von Änderungen, insbesondere in Bezug auf die Verwendung dieser Begriffe. Die folgenden Elemente sind in der Regel erklärt und definiert: Typen, Variablenund Funktionen.

  • Deklarieren gibt der Compiler nur ein symbolischer Name und ein “Typ” für diesen symbolischen Namen.
    • Beispielsweise teilt die Deklaration einer Variablen dem Compiler den Namen dieser Variablen und ihren Typ mit.
  • Definieren gibt dem Compiler die vollständigen Details eines Artikels:
    • Im Fall eines Typs gibt die Definition dem Compiler sowohl einen Namen als auch die detaillierte Struktur für diesen Typ.
    • Im Fall einer Variablen weist das Definieren den Compiler an, Speicher zuzuweisen (wo und wie viel), um eine Instanz dieser Variablen zu erstellen.

Allgemein gesagt können in einem Programm, das aus mehreren Dateien besteht, die Variablen, Typen und Funktionen sein erklärt in vielen Dateien, aber jeder kann nur haben eine Definition.

In vielen Programmiersprachen (z. B. C++) sind Deklaration und Definition leicht voneinander zu trennen. Dies ermöglicht eine “Vorwärtsdeklaration” von Typen, Variablen und Funktionen, wodurch Dateien kompiliert werden können, ohne dass diese Elemente erst später definiert werden müssen. In der Programmiersprache C dagegen Deklaration und Definition von Variablen sind ein und dasselbe. (Die einzige mir bekannte Ausnahme in der Programmiersprache C ist die Verwendung von Schlüsselwörtern extern um zuzulassen, dass eine Variable deklariert wird, ohne definiert zu werden.) Aus diesem Grund habe ich in einer früheren Bearbeitung dieser Antwort auf “Definition von Strukturen” und “Erklärung von Struktur [variables],” wobei die Bedeutung von “Erklärung einer Struktur [variable]” wurde so verstanden, dass eine Instanz (Variable) dieser Struktur erstellt wird.

  • können wir jeden Typ mit deklarieren _t Suffix? Ich dachte, dieses Suffix ist C99 vorbehalten. Liege ich falsch?

    – nowox

    4. März 2015 um 11:48 Uhr

  • Es ist wichtig zu beachten, dass selbstreferenzielle Strukturen einen Namen für die Struktur oder eine vorwärts deklarierte Typedef erfordern. Ich bevorzuge es zum Beispiel, wenn ich möchte, dass ein typisierter LinkedList-Knoten Folgendes schreibt: typedef struct node_t {void * data; struct node_t next; } Node; damit die Erklärung vollständig und prägnant ist.

    – aaroncarsonart

    29. Dezember 2015 um 15:59 Uhr

  • Im Ernst, das hat meine ganze Verwirrung über C struct gelöst. Vielen Dank!

    – langsam

    30. Januar 2019 um 22:40 Uhr

  • @MTV”Because the struct type is unnamed, you can't declare another such variable. So there can only ever be one instance of that type right?” Das ist richtig. Aus diesem Grund ist die Verwendung einer anonymen Struktur etwas, das Sie selten tun würden. Das einzige Mal, dass ich so etwas jemals getan habe, war, wenn ich nur vorübergehend eine lokale Struktur innerhalb einer Funktion benötige. Sicherlich, wenn Sie die Daten irgendwohin übergeben müssen Andernfalls würden Sie die Struktur benennen oder häufiger typedef. Und wenn mehrere Dateien Zugriff auf die Strukturdefinition benötigen, würden Sie sie in eine Header-Datei einfügen. Hoffe, das hilft.

    – Daniel Goldfarb

    26. Februar 2020 um 21:26 Uhr


  • Das Name in struct Name {}; wird Struktur-Tag genannt. Der Compiler verwendet dieses Tag, um die Definition zu finden. Dies ist wichtig, denn wenn Ihre Struktur auf sich selbst verweist (z. B. in einer verknüpften Liste), dann auf Sie muss Verwenden Sie andernfalls eine Struktur mit Tag, die Typedef-Deklaration ist noch nicht abgeschlossen und der Typname ist dem Compiler unbekannt. AFAIK ist dies der einzige Unterschied zwischen diesen beiden Arten der Definition von Strukturen.

    – Artronik

    5. Mai 2020 um 20:25 Uhr


Die Syntax ist von typedef ist wie folgt:

typedef old_type new_type

Bei Ihrem ersten Versuch haben Sie die definiert struct Book Typ und nicht Book. Mit anderen Worten, Ihr Datentyp wird aufgerufen struct Book und nicht Book.

In der zweiten Form haben Sie die richtige Syntax von verwendet typedefsodass der Compiler den aufgerufenen Typ erkennt Book.

  • Das ist nur die Syntax für einfache Fälle, ein Gegenbeispiel wäre typedef int x[5];oder typedef int (*p)();

    – MM

    7. November 2019 um 20:35 Uhr


Möchten Sie hinzufügen, indem Sie klären, wann Sie tatsächlich eine Variable deklarieren.

struct foo {
   int a;
} my_foo;

definiert foo und deklariert sofort eine Variable my_foo des struct foo Typ, was bedeutet, dass Sie es so verwenden können my_foo.a = 5;

Allerdings, weil typedef Syntax folgt typedef <oldname> <newname>

typedef struct bar {
   int b;
} my_bar;

ist nicht eine Variable deklarieren my_bar des Typs struct bar, my_bar.b = 5; ist illegal. Stattdessen gibt es dem einen neuen Namen struct bar Geben Sie die Form ein my_bar. Sie können jetzt die deklarieren struct bar tippe mit my_bar so was:

my_bar some_bar;

Die anderen Antworten sind alle richtig und nützlich, aber vielleicht länger als nötig. Mach das:

typedef struct Book Book;
typedef struct Books Books;
typedef struct Author Author;

struct Book {
    ... as you wish ...
};

struct Author {
    ... as you wish ...
};

struct Books {
    ... as you wish ...
};

Sie können Ihre definieren struct‘s in beliebiger Reihenfolge, sofern sie nur enthalten Zeiger zu anderen struct‘s.

Sie müssen nur Autor definieren, bevor Sie Buch definieren.

Sie verwenden Author in Book, also muss es vorher definiert werden.

  • Danke für die schnellen Antworten. Es gibt keinen Fehler beim Definieren von Buch vor Autor, überprüft in Kernighan und Ritchies Buch.

    – Alex Sobczyk

    18. Juli 2013 um 10:19 Uhr

  • Ich habe mich geirrt, anscheinend werden die Fehler behoben, wenn ich die Position ändere. Ich muss noch ein bisschen lernen. (Entschuldigung für den doppelten Kommentar, erster Timer im Stapelüberlauf: P)

    – Alex Sobczyk

    18. Juli 2013 um 10:28 Uhr

Benutzeravatar von aiked0
aiked0

Ich denke, wird Ihnen helfen, zu verstehen.
http://www.tutorialspoint.com/cprogramming/c_typedef.htm

bookstore.c:8:2: error: unknown type name ‘Author’
bookstore.c:21:2: error: unknown type name ‘Book’

Diese werden erstellt, weil Sie sie definieren müssen, bevor Sie sie verwenden. Verschieben Sie die Struktur “Autor” & “Bücher” über die Struktur “Buch”. Dies wird es lösen.

Die Warnung, die Sie erhalten, erklärt auch, warum ein Problem vorliegt. Der Compiler identifiziert “typedef struct Author” als nicht erforderlich, da Sie die Struktur nicht richtig typdefiniert haben, sodass der Compiler nichts Nützliches zum “Lesen” hat.

Da Sie bereits wissen, sollte die Antwort in dieser Form erfolgen

typedef struct {
 ...
 ... 
 ...
} struct-name;

bleib dabei.

  • Danke für die schnellen Antworten. Es gibt keinen Fehler beim Definieren von Buch vor Autor, überprüft in Kernighan und Ritchies Buch.

    – Alex Sobczyk

    18. Juli 2013 um 10:19 Uhr

  • Ich habe mich geirrt, anscheinend werden die Fehler behoben, wenn ich die Position ändere. Ich muss noch ein bisschen lernen. (Entschuldigung für den doppelten Kommentar, erster Timer im Stapelüberlauf: P)

    – Alex Sobczyk

    18. Juli 2013 um 10:28 Uhr

1415060cookie-checkC: Typedef-Strukturname {…}; VS typedef struct{…} name;

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy