Anfängerfragen zu `typedef struct` (ist Fork aus "Gemeinsame nette double linked list...")
-
Warum steht das erste typedef einzelnd und das zweite nicht?
Edit: Ah weil du node_t direkt schon im struct verwendest
Warum heißen die Dinger tag?
--> Ernstgemeinte Frage, will jetzt nicht mit dir über Namen streiten
-
C ist da anders als C++, wenn du den Datentyp eines
struct
benutzen möchtest musst dustruct
dazuschreiben, alsostruct MyStruct { ... }; int main() { struct MyStruct ms; }
Wenn man sich das
struct
sparen möchte muss man einen Alias pertypedef
erzeugen, und das funktioniert nicht für anonymestructs
. Also braucht man einen Dummynamen damit der C-Compiler nicht rummault, und da hat sich sowas wietypedef struct tagMyStruct { ... } MyStruct;
durchgesetzt. Ob das jetzt tagMyStruct oder MyStruct_tag heisst ist vollkommen egal.
-
Ah gut zu wissen
Und bei C++ ist das nicht nötig? Da kann ich einfach das Ding direkt so bennen wir ich möchte und muss kein struct dazu schreiben?
-
@Leon0402 sagte in Sollen wir gemeinsam eine nette Double-linked- oder vielleicht sogar Skip List in C schreiben?:
Ah gut zu wissen
Und bei C++ ist das nicht nötig? Da kann ich einfach das Ding direkt so bennen wir ich möchte und muss kein struct dazu schreiben?
Ich bin mir nicht sicher, ob du das richtige meinst.
C:
struct MeinCStruct { }; int main() { struct MeinCStruct mcs1; // korrekt MeinCStruct mcs2; // falsch }
Weil das nervt, macht man
typedef struct MeinCStruct { } MeinCStruct; int main() { MeinCStruct mcs1; // Geht jetzt korrekt struct MeinCStruct mcs2; // geht auch noch, aber warum sollte man? }
In C++ geht das direkt ohne typedef:
struct MeinCppStruct { }; int main() { MeinCppStruct mcs1; // korrekt struct MeinCppStruct mcs2; // Geht aus Kompatibilitätsgünden auch, ist aber sehr unüblich }
Da das typedef einen Alias einführt (in meinem Beispiel den Namen
MeinCStruct
anstelle vonstruct MeinCStruct
) braucht der Aliasname auch nicht zwingend etwas mit dem Structnamen zu tun haben, siehe bei Swordfish:typedef struct list_tag { node_t *head; node_t *tail; size_t length; } list_t;
Es ist nur recht unüblich, unterschiedliche Namen zu wählen, weil es dann einfacher nachvollziehbar ist.
Es ist auch nicht ganz unüblich (und erlaubt) den Namen des structs gleich ganz weg zu lassen:
typedef struct { // Erlaubt! node_t *head; node_t *tail; size_t length; } list_t;
-
Ja ich denke das meinte ich
Und wie sieht es aus, wenn man das struct selbst wieder im struct nutzt wie im Code von Fish
typedef struct node_tag node_t; struct node_tag { void *data; node_t *next; node_t *prev; };
darf ich hier das ganze auch einfach so machen:
typedef struct node_tag { void *data; node_tag *next; node_tag *prev; } node_t;
Oder müsste ich hier vor das node_tag (in C) ebenfalls dann ein struct schreiben?
Vom Namen her finde ich es interessant, dass man "tag" nutzt, ich hätte einfach "node" und "node_t" genuzt.
-
Nein, die Idee ist doppelt falsch, und ich denke anhand der frage, du hast das mit dem typedef immer noch nicht verstanden.
Daher nochmal:
In C:struct Irgendwas { };
Es gibt jetzt keinen Typ mit Namen
Irgendwas
. Es gibt nur den Typstruct Irgendwas
und das "struct" ist essentieller Bestandteil des Namens, der nicht weg gelassen werden darf. Der Typ hat halt einfach einen Namen, der aus zwei Worten besteht. Denk irgendwie analog zuunsigned long int
. Typen dürfen halt auch aus mehreren Worten bestehen und machmal tun sie das auch.Aber genauso wie du schreiben dürftest
typedef unsigned long int my_int;
darfst du auch schreiben
typedef struct Irgendwas IrgendwasAnderes;
Da, wie gesagt, der Name
Irgendwas
hier noch nicht belegt ist (es gibt nurstruct Irgendwas
) ist dies hier auch völlig regulär:typedef struct Irgendwas Irgendwas;
Jetzt gibt es einen Typen mit Namen
Irgendwas
und das ist ein Alias für den eigentlichen Typenstruct Irgendwas
.Da C viel verschachtelte Syntax erlaubt, darf man typedef und struct-Definition auch alles in einem machen:
struct Irgendwas { int i; }; typedef struct Irgendwas Irgendwas;
kann man zusammenfassen als
typedef struct Irgendwas { int i; } Irgendwas;
Und wichtig: Die ganzen Typennamen existieren erst nach dem Semikolon, das ihre Definition abschließt:
struct Irgendwas { int i; }; // Name `struct Irgendwas` existiert ab hier typedef struct Irgendwas Irgendwas; // Name `Irgendwas` existiert ab hier
oder mit der Kurzfassung
typedef struct Irgendwas { int i; } Irgendwas; // Die Namen `struct Irgendwas` und `Irgendwas` existieren ab hier
Daher geht deine Idee mehrfach nicht:
typedef struct node_tag { void *data; node_tag *next; node_tag *prev; } node_t;
- Müsste das in Zeile 3/4 entweder
node_t
oderstruct node_tag
heißen. Es gibt nirgendwo einen Typen mit Namennode_tag
. - Der Typ
struct node_tag
bzw.node_t
ist erst nach dem Semikolon in Zeile 5 bekannt, und kann vorher nicht benutzt werden. Daher geht das prinzipiell überhaupt gar nicht, und man muss das so machen wie Swordfish. also erst den Namen bekannt machen, und ihn erst dann in einer Definition benutzen.
- Müsste das in Zeile 3/4 entweder
-
Ich habe die Fragen zu
typedef struct
abgetrennt. Der Zweck des anderen Threads war eine Diskussion darüber, wie man das dortige Problem in C auf höchstem Designniveau anpacken würde, ohne Ablenkung durch Grundsatzfragen.
-
Stimmt, wenn ich drüber nachdenke muss man das ja auch in C++ so machen (also der Punkt 2).
Meine Denkweise war, dass das struct vlt. eher so wie typename funktioniert. Man braucht es in gewissen Kontexten, weil sonst der Compiler verwirrt ist. Daher dachte ich im struct selbst, weiß der Compiler vlt. das es um ein struct geht
Aber mal abgesehen davon, dass das Szenario überhaupt keinen Sinn ergibt wegen Punkt 2, scheint das struct ja hier tatsächlich wirklich teil des Namens zu sein.Gibt es einen Grund, warum das in C so realisiert wurde?
Edit: Nochmal nachgedacht, in C++ ist das doch nicht so, oder? Solange ich einen Pointer nutze, sollte das gehen?
Edit 2: Ich weiß, dass ich hier laufend C und C++ vermische, aber grade um die Unterschiede geht es mir ebenLücke im Kategorisierungssytem vom Forum ^^
-
Stimmt, das war nicht ganz richtig. Du kannst sehr wohl
typedef struct node_tag { void *data; struct node_tag *next; struct node_tag *prev; } node_t;
schreiben, aber nicht
typedef struct node_tag { void *data; node_t *next; node_t *prev; } node_t;
-
Ah perfekt, das ergibt Sinn, vielen Dank
-
@SeppJ sagte in Anfängerfragen zu
typedef struct
(ist Fork aus "Gemeinsame nette double linked list..."):Ich habe die Fragen zu
typedef struct
abgetrennt. Der Zweck des anderen Threads war eine Diskussion darüber, wie man das dortige Problem in C auf höchstem Designniveau anpacken würde, ohne Ablenkung durch Grundsatzfragen.Danke! Und auch danke für die Erklärbärarbeit.
@Leon0402 Vielleicht hilft auch https://en.cppreference.com/w/c/language/name_space
-
@Swordfish In der Tat sehr hilfreich! Jetzt ist mir auch klar, woher der Zusatz "Tag" kommt.
Ich finde vor dem Hintergrund meine Annahme, dass:
typedef struct node_tag { void *data; node_t *next; node_t *prev; } node_t;
auch gar nicht mal so weit hergeholt. Nach dem Motto: Im Tag Name Space kann ich alles aus diesem Namespace ohne den Zusatz verwenden.
Aber so wie ich das verstehe, ist der C Namespace nicht das selbe wie ein C++ Namespace, wo quasi alles in dem namespace landet, sondern eben nur der identifier landet in dem Namespace.
-
@Leon0402 sagte in Anfängerfragen zu `typedef struct` (ist Fork aus "Gemeinsame nette double linked list..."):
Aber so wie ich das verstehe, ist der C Namespace nicht das selbe wie ein C++ Namespace
Das sind einfach "Kategorien" von Namen. Hat mit namespaces in C++ überhaupt nichts zu tun.