Was ist ‘Forward Declaration’ und der Unterschied zwischen ‘typedef struct X’ und ‘struct X’?

Lesezeit: 8 Minuten

Benutzeravatar von r_goyal
r_goyal

Ich bin ein Anfänger in der C-Programmierung und kenne den Unterschied zwischen struct Typdeklaration und typedef struct-Deklaration. Ich bin auf eine Antwort gestoßen, die besagt, dass, wenn wir a definieren struct wie:

typedef struct { 
    some members;
} struct_name;

Dann ist es so, als würde man einer anonymen Struktur einen Alias ​​geben (da sie keinen Tag-Namen hat). Es kann also nicht für die Vorwärtsdeklaration verwendet werden. Ich weiß nicht, was Vorwärtserklärung meint.

Außerdem wollte ich das für den folgenden Code wissen:

typedef struct NAME { 
    some members;
} struct_alias;

Gibt es einen Unterschied zw NAME und struct_alias? Oder sind beide gleich
struct_alias ist ein Alias ​​von struct NAME ?

Können wir außerdem eine Variable vom Typ deklarieren struct NAME wie diese:

struct_alias variable1;

und/oder wie:

struct NAME variable2;

oder wie:

NAME variable3; 

Benutzeravatar von Sergey L
Sergej L.

struct Forward-Deklarationen können nützlich sein, wenn Sie Schleifen-Struct-Deklarationen benötigen. Beispiel:

struct a {
    struct b * b_pointer;
    int c;
};

struct b {
    struct a * a_pointer;
    void * d;
};

Wann struct a wird erklärt, dass es die Spezifikationen nicht kennt struct b noch, aber Sie können darauf verweisen.

Wenn Sie eine anonyme Struktur typdefinieren, erlaubt Ihnen der Compiler nicht, ihren Namen vor der Typdefinition zu verwenden.

Das ist illegal:

struct a {
    b * b_pointer;
    int c;
};

typedef struct {
    struct a * a_pointer;
    void * d;
} b;

// struct b was never declared or defined

Dies ist jedoch legal:

struct a {
    struct b * b_pointer;
    int c;
};

typedef struct b {
    struct a * a_pointer;
    void * d;
} b;

// struct b is defined and has an alias type called b

Also das ist:

typedef struct b b;
// the type b referes to a yet undefined type struct b

struct a {
    b * struct_b_pointer;
    int c;
};

struct b {
    struct a * a_pointer;
    void * d;
};

Und das (nur in C, illegal in C++):

typedef int b;

struct a {
    struct b * struct_b_pointer;
    b b_integer_type;
    int c;
};

struct b {
    struct a * a_pointer;
    void * d;
};

// struct b and b are two different types all together. Note: this is not allowed in C++

  • aber was ist mit dem NAME Ant struct_alias?? und was wäre, wenn ich ” struct b b_pointer ” in “struct a” Deklaration trotz “bb_pointer”??

    – r_goyal

    6. September 2013 um 14:17 Uhr

  • @akash_sinha13134 das wäre gültig, wenn struct b wird später definiert. Aber nicht, wenn Sie eine anonyme Struktur eingeben b. typedef struct b { struct a * a_pointer; void * d; } b; wäre gültig. Typedef-Namen befinden sich nicht im selben Namensraum wie Strukturnamen. Sie können eine haben struct b und eine Art b das sind ganz andere. Ich denke, einige Verwirrung kommt hier daher, dass C++ diese Typedef standardmäßig verwendet – C nicht.

    – Sergej L.

    6. September 2013 um 14:21 Uhr


Erklärung weiterleiten ist ein Versprechen, etwas zu definieren, das Sie einem Compiler an dem Punkt geben, an dem die Definition nicht möglich ist. Der Compiler kann Ihr Wort verwenden, um andere Deklarationen zu interpretieren, die er sonst nicht interpretieren könnte.

Ein gängiges Beispiel ist a struct entworfen, um ein Knoten in einer verketteten Liste zu sein: Sie müssen einen Zeiger auf einen Knoten in die setzen structaber der Compiler würde dies nicht ohne eine Vorwärtsdeklaration oder ein Tag zulassen:

// Forward declaration
struct element;
typedef struct {
    int value;
    // Use of the forward declaration
    struct element *next;
} element; // Complete definition

und kann daher nicht für die Vorwärtsdeklaration verwendet werden

Ich denke, der Punkt des Autors war, dass Sie Ihre geben struct Ein Tag würde einer Vorwärtsdeklaration entsprechen:

typedef struct element {
    int value;
    // No need for a forward declaration here
    struct element *next;
} element;

  • Bedeutet das, dass dat typedefs nicht zulassen, dass auf den typdefinierten Bezeichner verwiesen wird, bevor sie typdefiniert sind? wenn das wat heißt VORWÄRTSERKLÄRUNG) dann versteht der Compiler nicht, was deklariert wird??? oder es kommt zu einer Kollision wie in Ihrem Beispiel dazwischen struct element; und typedef struct{}element; ??

    – r_goyal

    6. September 2013 um 14:29 Uhr

  • @dasblinkenlight .. + ich glaube, ich habe die Antwort bekommen, dass wenn wir keinen Tag-Namen für eine Strukturvorlage haben, dann können wir ihn nicht deklarieren, weil es nichts gibt, auf das verwiesen werden kann … wie wenn wir eine Struktur deklarieren und verwenden müssen at Eine Programmzeile und eine Datenstruktur werden hundert Zeilen später definiert, und wir werden keinen Tagnamen haben, auf den verwiesen werden kann, um ihn weiterzuleiten.

    – r_goyal

    6. September 2013 um 14:33 Uhr

  • @akash_sinha13134 “bedeutet das das typedefs nicht zulassen typedef-ed Bezeichner, auf die verwiesen werden soll, bevor sie es sind typedef-ed”? Richtig. “wird es eine Kollision wie in Ihrem Beispiel zwischen geben struct element; und typedef struct{}element;” Nein, es würde keine Kollision geben: das Beispiel wird kompiliert und läuft gut – Schau mal.

    – Sergej Kalinitschenko

    6. September 2013 um 14:33 Uhr

  • @akash_sinha13134 Ihr Verständnis ist richtig. Eine zusätzliche Situation, wenn Sie a vorwärts deklarieren möchten struct ist, wenn Sie einen Zeiger darauf deklarieren möchten, ohne die eigentliche Definition einer Struktur einbringen zu müssen. Dadurch können Sie Kompilierzeitabhängigkeiten in Situationen einsparen, in denen Sie a behandeln struct als “Black Box”, auf die ein Zeiger zeigt, dh wenn Sie ihre Interna nicht kennen müssen.

    – Sergej Kalinitschenko

    6. September 2013 um 14:37 Uhr

  • danke @dasblinkenlight … aber wie speichert es die Abhängigkeiten der Kompilierzeit? Denn immer wenn ich auf die Struktur für die Vorwärtsdeklaration verweise, sucht der Compiler nach der Stelle, an der die Struktur im Programm definiert ist … und wieso es Abhängigkeiten zur Kompilierzeit spart … ich kann es nicht verstehen …

    – r_goyal

    6. September 2013 um 14:54 Uhr

Erklärung weiterleiten ist eine Deklaration, die einer tatsächlichen Definition vorangeht, normalerweise zu dem Zweck, auf den deklarierten Typ verweisen zu können, wenn die Definition nicht verfügbar ist. Natürlich kann nicht alles mit der deklariert-nicht-definiert-Struktur gemacht werden, aber in bestimmten Kontexten ist es möglich, sie zu verwenden. Solcher Typ heißt unvollständig, und es gibt eine Reihe von Einschränkungen bei der Verwendung. Zum Beispiel:

struct X; // forward declaration

void f(struct X*) { }  // usage of the declared, undefined structure

// void f(struct X) { }         // ILLEGAL
// struct X x;                  // ILLEGAL
// int n =sizeof(struct X);     // ILLEGAL

// later, or somewhere else altogether
struct X { /* ... */ };

Dies kann zB nützlich sein, um zirkuläre Abhängigkeiten aufzuheben oder die Kompilierungszeit zu verkürzen, da die Definitionen normalerweise erheblich größer sind und daher mehr Ressourcen zum Analysieren benötigt werden.

In deinem Beispiel struct NAME und struct_alias sind in der Tat gleichwertig.

struct_alias variable1;
struct NAME variable2;

sind richtig;

NAME variable3;

ist nicht, wie in C die struct Schlüsselwort ist erforderlich.

  • @marcin .. aber in C kann ich bei der Verwendung von typedef die Verwendung des Schlüsselworts struct wie in struct_alias variable1 weglassen; Warum kann ich das Schlüsselwort struct vor NAME nicht weglassen?

    – r_goyal

    6. September 2013 um 14:13 Uhr

  • @r_goyal Sie können es für den ALIAS weglassen, nicht für den NAMEN. Ein typdef erstellt den Alias, der der Ersatz für ‘struct NAME’ ist.

    – Allan Jude

    5. Dezember 2017 um 4:12 Uhr

struct_alias und struct NAME sind gleich ,struct_alias ist ein Alias ​​für struct NAME

Diese sind beide gleich und erlaubt

struct_alias variable1;  

struct NAME variable1; 

das ist illegal

NAME variable3;   

Siehe diesen Artikel auf Erklärung weiterleiten

Benutzeravatar von Michael Beer
Michael Bier

Wie bereits erwähnt, ist eine Vorwärtsdeklaration in C/C++ die Deklaration von etwas, bei dem die eigentliche Definition nicht verfügbar ist. Es ist eine Deklaration, die dem Compiler sagt, “es gibt einen Datentyp ABC”.

Nehmen wir an, dies ist ein Header für einen Schlüssel/Wert-Speicher my_dict.h :

...
struct my_dict_t;
struct my_dict_t* create();

char* get_value(const struct my_dict_t* dict, const char* name);
char* insert(struct my_dict_t* dict, const char* name, char* value);
void destroy(struct my_dict_t* dict);
...

Sie wissen nichts darüber my_dict_taber eigentlich müssen Sie für die Nutzung des Stores nicht wissen:

#include "my_dict.h"
...
struct my_dict_t* dict = create();
if(0 != insert(dict, "AnEntry", strdup("AValue"))) {
    ...
}
...

Der Grund dafür ist: Sie verwenden nur POINTERS auf die Datenstruktur.

POINTERS sind nur Zahlen, und um mit ihnen umzugehen, müssen Sie nicht wissen, worauf sie zeigen.

Dies spielt nur eine Rolle, wenn Sie versuchen, tatsächlich darauf zuzugreifen, z

struct my_dict_t* dict = create();
printf("%s\n", dict->value);  /* Impossible if only a forward decl is available */

Für die Implementierung der Funktionen benötigen Sie also eine tatsächliche Definition von my_struct_t. Sie können dies in der Quelldatei tun my_dict.c so:

#include "my_dict.h"

struct my_dict_t {
    char* value;
    const char* name;
    struct my_dict_t* next;
}

struct my_dict_t* create() {
    return calloc(1, sizeof(struct my_dict_t));
}

Dies ist praktisch für verschiedene Situationen, wie z

  • Zum Auflösen von zirkulären Abhängigkeiten, wie Sergei L. erklärt hat.
  • Zur Kapselung, wie im obigen Beispiel.

Bleibt also die Frage: Warum können wir die Forward-Deklaration überhaupt nicht weglassen, wenn wir die obigen Funktionen verwenden? Am Ende würde es genügen, wenn der Compiler das alles wüsste dict sind Hinweise.

Der Compiler führt jedoch Typprüfungen durch: Er muss überprüfen, ob Sie so etwas nicht tun

...
int i = 12;
char* value = get_value(&i, "MyName");
...

Es muss nicht wissen wie my_dict_t sieht aus wie, aber es muss das wissen &i ist nicht der Zeigertyp get_value() erwartet.

  • +1 Dies ist die einzige Antwort hier, die erklärt, wie Zeiger auf Typen verwendet werden können, deren Definitionen noch nicht verfügbar sind, um Fehler vom Typ “Fehler: Feld hat unvollständigen Typ” zu vermeiden.

    – ZeZNiQ

    6. April 2020 um 2:20 Uhr

  • +1 Dies ist die einzige Antwort hier, die erklärt, wie Zeiger auf Typen verwendet werden können, deren Definitionen noch nicht verfügbar sind, um Fehler vom Typ “Fehler: Feld hat unvollständigen Typ” zu vermeiden.

    – ZeZNiQ

    6. April 2020 um 2:20 Uhr

1411550cookie-checkWas ist ‘Forward Declaration’ und der Unterschied zwischen ‘typedef struct X’ und ‘struct X’?

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

Privacy policy