Forum: Compiler & IDEs Definition struct


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Walter T. (nicolas)


Bewertung
1 lesenswert
nicht lesenswert
Hallo zusammen,

ich gehe gerade durch (fremden) C++-Quelltext, bei dem structs sinngemäß 
so definiert sind:
1
struct _libname_structname_t
2
{
3
    uint8_t a, b, c, d;
4
};
5
6
typedef struct _libname_structname_t libname_structname_t;

Ich verstehe allerdings nicht, was mit diesem Design Pattern bezweckt 
werden soll.

Kennt sich jemand genug in C++ aus, den Zweck zu erklären?

Viele Grüße
W.T.

von Nase (Gast)


Bewertung
1 lesenswert
nicht lesenswert
Man kann auf diese Weise sowohl in C als auch in C++ mit 
"libname_structname_t NAME" eine Strukturvariable definieren. Ohne das 
Typedef ginge das nur in C++ und in C müsste man noch "struct" 
davorsetzen, weil Strukturen in C einen eigenen Namensraum haben.

von Walter T. (nicolas)


Bewertung
1 lesenswert
nicht lesenswert
Verstehe ich nicht. In C würde ich es so machen:
1
typedef struct libname_structname_t
2
{
3
    uint8_t a, b, c, d;
4
} libname_structname_t;

oder auch:
1
struct libname_structname_t
2
{
3
    uint8_t a, b, c, d;
4
} libname_structname_t;
5
6
typedef struct libname_structname_t libname_structname_t;
Bei structs und andere Typen in unterschiedlichen namespaces sind, gibt 
es keine Kollision. Warum die Erweiterung mit dem Unterstrich?

: Bearbeitet durch User
von Rufus Τ. F. (rufus) (Moderator) Benutzerseite


Bewertung
1 lesenswert
nicht lesenswert
Walter T. schrieb:
> In C würde ich es so machen:

Das geht auch in C++ so.

Walter T. schrieb:
> oder auch:

Vorsicht! Das legt eine Variable namens libname_structname_t an. Das 
ist sicher nicht, was Du erreichen möchtest.

Das zweite libname_structname_t hinter der geschlossenen Klammer muss 
weg.

Walter T. schrieb:
> Warum die Erweiterung mit dem Unterstrich?

Einen wirklichen Grund dafür gibt es nicht, das mag eine Gewöhnung des 
Autors sein.


Tatsächlich kann man auch namenlose Strukturen zusammen mit typedef 
verwenden und hat dann nicht den -überflüssigen- Strukturnamen:
1
typedef struct
2
{
3
    uint8_t a, b, c, d;
4
} libname_structname_t;

Das funktioniert in C und in C++ gleichermaßen.

von Walter T. (nicolas)


Bewertung
0 lesenswert
nicht lesenswert
Rufus Τ. F. schrieb:
> Das zweite libname_structname_t hinter der geschlossenen Klammer muss
> weg.

Stimmt. Copy-Paste-Fehler.

Rufus Τ. F. schrieb:
> Einen wirklichen Grund dafür gibt es nicht, das mag eine Gewöhnung des
> Autors sein.

Danke!


Rufus Τ. F. schrieb:
> Tatsächlich kann man auch namenlose Strukturen zusammen mit typedef
> verwenden

In einigen IDEs ist es praktisch, wenn alle structs Namen haben. Aber 
ansonsten: Klar.

: Bearbeitet durch User
von Tom (Gast)


Bewertung
1 lesenswert
nicht lesenswert
Walter T. schrieb:
> Bei structs und andere Typen in unterschiedlichen namespaces sind, gibt
> es keine Kollision

In der Steinzeit war das wohl noch nicht so:
https://blogs.msdn.microsoft.com/oldnewthing/20080326-00/?p=22993

von Walter T. (nicolas)


Bewertung
0 lesenswert
nicht lesenswert
Danke! Das ist lesenswert.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Bewertung
1 lesenswert
nicht lesenswert
Tom schrieb:
> Walter T. schrieb:
>> Bei structs und andere Typen in unterschiedlichen namespaces sind, gibt
>> es keine Kollision
>
> In der Steinzeit war das wohl noch nicht so:
> https://blogs.msdn.microsoft.com/oldnewthing/20080326-00/?p=22993

Ich trau' Microsoft keinerlei Expertise hinsichtlich historischem C
zu.

Wenn ich mir bei Dennis Ritchie das C Reference Manual der 6th UNIX
Edition ansehe (von 1975):

https://www.bell-labs.com/usr/dmr/www/cman.pdf

… dann gibt es da sehr wohl bereits getrennte Namensräume für struct
tags und Variablen.  Zu dieser Zeit dürfte Microsoft noch komplett in
Assembler programmiert haben.

Dafür gab es damals eine anderweitige Absonderlichkeit: die Elemente
von structs teilten sich alle einen Namensraum!  Mit dieser Krücke
konnte man structs einrichten, deren erste Komponenten alle gleich
waren und einander Aliase bildeten – denn unions gab es offenbar noch
nicht.

Das erklärt, warum man in altem Unix-Sourcecode den struct-Elementen
immer einen oder zwei Buchstaben und einen Unterstrich vorangestellt
hat, bspw. st_mode oder st_ino in struct stat.

von Rolf M. (rmagnus)


Bewertung
0 lesenswert
nicht lesenswert
Jörg W. schrieb:
> Ich trau' Microsoft keinerlei Expertise hinsichtlich historischem C
> zu.

Aber in aktuellem C?

> Das erklärt, warum man in altem Unix-Sourcecode den struct-Elementen
> immer einen oder zwei Buchstaben und einen Unterstrich vorangestellt
> hat, bspw. st_mode oder st_ino in struct stat.

Aha! Ich hatte mich durchaus schon gefragt, wozu das gut sein soll, z.B. 
auch bei der struct timeval mit tv_sec und tv_usec.

von Tom (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Hier ist das Manual von einem antiken Lattice-C-Compiler, den MS 1983 
laut https://sites.google.com/site/pcdosretro/mschist als ihren 
C-Compiler 1.0 verkauft hat: 
https://winworldpc.com/download/c3960054-5d5a-6a11-c3a5-c28fc2a3c388

Jörg W. schrieb:
> anderweitige Absonderlichkeit
Die ist in dem Manual übrigens ausdrücklich ausgeschlossen (Seite 2-2). 
Ob es (ebenfalls vom Standard abweichend) dort einen gemeinsamen 
Namensraum für struct tags und Variablen gab, habe ich nicht gefunden.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Bewertung
1 lesenswert
nicht lesenswert
Rolf M. schrieb:
>> Ich trau' Microsoft keinerlei Expertise hinsichtlich historischem C
>> zu.
>
> Aber in aktuellem C?

Solange sich "aktuell" auf ANSI 89 / ISO 90 bezieht, ja. :)

von Rolf M. (rmagnus)


Bewertung
0 lesenswert
nicht lesenswert
Jörg W. schrieb:
>> Aber in aktuellem C?
>
> Solange sich "aktuell" auf ANSI 89 / ISO 90 bezieht, ja. :)

Das mag für Microsoft noch immer als aktuell gelten, aber ich würde es 
dann doch eher zum historischen C zählen. ;-)

von W.S. (Gast)


Bewertung
-2 lesenswert
nicht lesenswert
Walter T. schrieb:
> Ich verstehe allerdings nicht, was mit diesem Design Pattern bezweckt
> werden soll.

Der einzige Zweck, der dahinter stehen mag ist der, daß der Autor das 
Wort "struct" nicht bei den Variablendeklarationen hinschreiben will. 
Also Faulheit, sonst nix.

Bedenke, daß "typedef" nichts anderes macht, als einem bekannten Typ 
einen zweiten Namen zu geben, so daß man anschließend beide Namen für 
denselben Typ verwenden kann.

Man hätte es besser "rename" nennen sollen.

Es unterscheidet sich vom #define nur dadurch, daß es an anderer Stelle 
im Übersetzungsverlauf erledigt wird.

W.S.

von Dr. Sommer (Gast)


Bewertung
0 lesenswert
nicht lesenswert
W.S. schrieb:
> Man hätte es besser "rename" nennen sollen.
Eher "Alias". Der alte Name existiert ja immer noch.
> Es unterscheidet sich vom #define nur dadurch, daß es an anderer Stelle
> im Übersetzungsverlauf erledigt wird.

Und daher gibt es bei typedef auch keine Probleme mit Scope o.ä.

von Rolf M. (rmagnus)


Bewertung
0 lesenswert
nicht lesenswert
W.S. schrieb:
> Es unterscheidet sich vom #define nur dadurch, daß es an anderer Stelle
> im Übersetzungsverlauf erledigt wird.

Das ist Quatsch. Ein #define macht reine Textersetzung im Quellcode, 
typedef arbeitet direkt im Typsystem. Dadurch ergeben sich bei #define 
einige Fallstricke, und manche Sachen wie z.b. einen Namen für einen 
Funktionszeiger-Typ kann man mit #define so gar nicht machen.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert
W.S. schrieb:
> Der einzige Zweck, der dahinter stehen mag ist der, daß der Autor das
> Wort "struct" nicht bei den Variablendeklarationen hinschreiben will.

Dafür allein würde aber
1
typedef struct {...} foo_t;

genügen.  Falls die struct sich selbst (über Zeiger) referenzieren
können muss, braucht sie unbedingt einen struct tag, aber dann geht
auch
1
typedef struct foo_t {...} foo_t;

und man muss nicht unbedingt dieses unsinnige Doppelgemoppel mit dem
weiteren Unterstrich fabrizieren:
1
typedef struct _foo_t {...} foo_t;

Nur um dieses ging ja der Thread.

Übrigens ist die zweite Variante oben sogar in C++ zulässig.  Dort
würde ja bereits durch die struct selbst ein "foo_t" im entsprechenden
Namensraum erzeugt, aber die zusätzliche Erzeugung des gleichen Namens
mithilfe eines typedef ist explizit zugelassen.  Dadurch kann man
entsprechende Headerfiles sowohl für C als auch C++ ohne Änderungen
oder #ifdef oder dergleichen benutzen.

: Bearbeitet durch Moderator
von Nop (Gast)


Bewertung
1 lesenswert
nicht lesenswert
W.S. schrieb:

> Es unterscheidet sich vom #define nur dadurch, daß es an anderer Stelle
> im Übersetzungsverlauf erledigt wird.

Das ist Unsinn, wie die meisten Deiner Aussagen zum Thema C.
1
#define d_ptr struct s *
2
typedef struct s * t_ptr;

Was ist der Unterschied?
1
d_ptr ptr1, ptr2;
2
t_ptr ptr3, ptr4;

Das Zweitere tut das, wonach es aussieht, zwei Pointer deklarieren. Aber 
das Erstere macht Textersetzung, expandiert also zu:
1
struct s * ptr1, ptr2;

Mit anderen Worten, ptr2 ist vom Typ struct s und nicht etwa ein Pointer 
darauf. Wenn man defines zum typedefen mißbraucht, kriegt man solche 
überraschenden Fehler raus.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.