Hallo zusammen,
ich habe in einer Datei mit dem Namen my_types.h folgendes stehen:
1
typedefstructA_{
2
uint8a;
3
uint8b;
4
}A;
Nun gibt es in meinem Projekt mehrere .c Dateien, welche den Typ A
verwenden. Deshalb habe ich oben in jeder dieser .c Datein oben #include
"my_types.h" eingetragen.
Beim compilieren bekomme ich jetzt den Fehler, dass der Typ A bereits
deklariert sei (was ja auch stimmt, weil die my_types.h ja auch für jede
.c Datei eingebunden wird). Wie kann ich dieses Problem umgehen?
Georg schrieb:> Beim compilieren bekomme ich jetzt den Fehler, dass der Typ A bereits> deklariert sei (was ja auch stimmt, weil die my_types.h ja auch für jede> .c Datei eingebunden wird).
Das Problem entsteht nicht dadurch, dass es in mehreren .c-Dateien
eingebunden ist, sondern dass es in einer .c-Datei mehrfach eingebunden
ist.
Stichwort wäre "include guard".
Ich hätte ja darauf getippt, dass der Namen für den Typ zu kurz ist und
deshalb zufällig noch für einen anderen Typ herhalten musste.
Ich bin ja auch tippfaul, aber ein wenig mehr geht schon.
Wenn du das Dingens sowieso nie als „struct A_“ benutzen willst, kannst
du den struct-Namen auch getrost weglassen. Der verunreinigt nur
unsinnig den Namensraum. Wenn man als generelle Policy alles mit
typedefs abwickelt, braucht man struct-Namen eigentlich nur, um
innerhalb der struct-Definition selbst schon darauf zugreifen zu können
(in Form eines Zeigers).
Außerdem wäre es auch völlig legitim, das Dingens „struct A“ zu nennen.
In C haben structs einen vom Rest getrennten Namensraum (man definiert
damit also ein „A“ sowohl im allgemeinen als auch im struct-Raum). In
C++ wiederum begründet „struct A“ einen Namen „A“, der auch ohne das
Schlüsselwort „struct“ fürderhin benutzt werden darf, ganz ohne typedef
- aber ein gleichnamiger typedef ist dennoch gestattet.
Die drei gesenkten Daumen sollten Dir reichen. :)
(Nero halt)
Sollte man vielleicht in diesem Zusammenhang noch etwas über das
typische "#ifndef" im Header sagen?
Framulestigo schrieb:> Die drei gesenkten Daumen sollten Dir reichen. :)> (Nero halt)
Die Aussage ist aber Quatsch. Wenn ein Strukturname nicht gebraucht wird
(nie, gar nicht), dann ist der Name über flüssig.
> Sollte man vielleicht in diesem Zusammenhang noch etwas über das> typische "#ifndef" im Header sagen?
Die Frage war schon lange, ausreichend und richtig beantwortet.
Ich habe schon öfters gesehen, dass die Compiler sich in den
Fehlermeldungen dann auf die anonymen structs bezogen haben. Also sowas
wie
struct unknown4711 has no member x
Deswegen bin ich auch eher dafür, keine anonymen structs zu haben.
Ich kann gerade leider nicht mehr sagen, welche Compiler das waren
(vielleicht IAR oder TI CCS?). Zuhause habe ich auf die Schnelle mit
Visual Studio 2017 und Mingw 5.30 getestet und die geben vernünftige
Fehlermeldungen aus.
Markus K. schrieb:> Ich habe schon öfters gesehen, dass die Compiler sich in den> Fehlermeldungen dann auf die anonymen structs bezogen haben. Also sowas> wie> struct unknown4711 has no member x>> Deswegen bin ich auch eher dafür, keine anonymen structs zu haben.
Das ist natürlich nicht schön. Der Compiler sollte zumindest in der Lage
sein, den Namen des neuen Typs in der Fehlermeldung zu nennen.
Alternativ sowas wie "anonymous struct". Wenn er das nicht macht ist das
mindestens nen Bugreport wert. Aber ein vernünftiger Compiler gibt ja
auch die Zeilennummer bei der Fehlermeldung an, so dass es nicht so
tragisch ist, da man den Fehler ja eh vor Ort beheben muss. Ich sehe da
keinen Grund gegen anonyme Strukturen.
mh schrieb:> Markus K. schrieb:>> Ich habe schon öfters gesehen, dass die Compiler sich in den>> Fehlermeldungen dann auf die anonymen structs bezogen haben. Also sowas>> wie>> struct unknown4711 has no member x> Aber ein vernünftiger Compiler gibt ja> auch die Zeilennummer bei der Fehlermeldung an, so dass es nicht so> tragisch ist, da man den Fehler ja eh vor Ort beheben muss.
Wenn der Code ein a.x = f.x ist (zwei verschiedene Structs, gleicher
Membername), dann ist das halt erst der Startpunkt. Dann muss man
erstmal rausfinden, welches der beiden Structs das war. Wenn das dann
verschachtelte Structs sind (a.b.c.x = d.e.f.x) und die Unterstützung
der IDE nicht funktioniert (also kein "Cursor auf die Variable und F10
drücken", z.B. weil man eine fremde Buildumgebung in ein Visual Studio
gepackt hat), dann passiert es schnell, dass man sich durch eine
handvoll header files kämpfen darf bis sieht wo es klemmt. Was man auch
hätte vermeiden können, wenn wenn man keine anonymen Structs benutzt
hätte.
Markus K. schrieb:> Ich kann gerade leider nicht mehr sagen, welche Compiler das waren> (vielleicht IAR oder TI CCS?).
Zumindest ist TI dafür berüchtigt, seine hauseigenen Compiler nicht.im
Griff zu haben...
Markus K. schrieb:> Wenn der Code ein a.x = f.x ist (zwei verschiedene Structs, gleicher> Membername), dann ist das halt erst der Startpunkt. Dann muss man> erstmal rausfinden, welches der beiden Structs das war. Wenn das dann> verschachtelte Structs sind (a.b.c.x = d.e.f.x) und die Unterstützung> der IDE nicht funktioniert (also kein "Cursor auf die Variable und F10> drücken", z.B. weil man eine fremde Buildumgebung in ein Visual Studio> gepackt hat), dann passiert es schnell, dass man sich durch eine> handvoll header files kämpfen darf bis sieht wo es klemmt. Was man auch> hätte vermeiden können, wenn wenn man keine anonymen Structs benutzt> hätte.
Also ein "vierfach wenn" (wenn Membernamen nichtssagend und wenn
geschachtelte anonyme Strukturen und wenn fehlende Unterstützung durch
die IDE und wenn mangehafte Fehlermeldung vom Compiler dann verursachen
anonyme Strukturen etwas mehr Arbeit). Wenn ich mit dir zusammen
arbeiten würde, würdest du mich damit nicht überzeugen.
mh schrieb:> Markus K. schrieb:>> Wenn der Code ein a.x = f.x ist (zwei verschiedene Structs, gleicher>> Membername), dann ist das halt erst der Startpunkt. Dann muss man>> erstmal rausfinden, welches der beiden Structs das war. Wenn das dann>> verschachtelte Structs sind (a.b.c.x = d.e.f.x) und die Unterstützung>> der IDE nicht funktioniert (also kein "Cursor auf die Variable und F10>> drücken", z.B. weil man eine fremde Buildumgebung in ein Visual Studio>> gepackt hat), dann passiert es schnell, dass man sich durch eine>> handvoll header files kämpfen darf bis sieht wo es klemmt. Was man auch>> hätte vermeiden können, wenn wenn man keine anonymen Structs benutzt>> hätte.>> Also ein "vierfach wenn" (wenn Membernamen nichtssagend und wenn> geschachtelte anonyme Strukturen und wenn fehlende Unterstützung durch> die IDE und wenn mangehafte Fehlermeldung vom Compiler dann verursachen> anonyme Strukturen etwas mehr Arbeit). Wenn ich mit dir zusammen> arbeiten würde, würdest du mich damit nicht überzeugen.
Die Lösung wäre, im Zweifel, um garantiert in jeder Hinsicht portabel zu
sein, nur den kleinsten gemeinsamen Nenner aus möglichen Compilern,
möglichen IDEs und möglichen Programmierern zu benutzen.
Zum Glück ist das keine verbindliche Regel.
Carl D. schrieb:> Die Lösung wäre, im Zweifel, um garantiert in jeder Hinsicht portabel zu> sein, nur den kleinsten gemeinsamen Nenner
Das wäre K&R-C, also C noch vor C89.
mh schrieb:> Also ein "vierfach wenn" (wenn Membernamen nichtssagend
Das funktioniert leider auch mit guten Namen. Immer wenn man in zwei
verschiedenen Structs members mit dem gleichen Namen benutzt, z.B. weil
damit das selbe gemeint ist.
> und wenn geschachtelte anonyme Strukturen
Die Prämisse in der Diskussion war doch, dass man alle Strukturen anonym
macht. Dann sind auch die geschachtelten Strukturen anonym.
> und wenn fehlende Unterstützung durch die IDE und> wenn mangehafte Fehlermeldung vom Compiler dann verursachen> anonyme Strukturen etwas mehr Arbeit).> Wenn ich mit dir zusammen> arbeiten würde, würdest du mich damit nicht überzeugen.
Dann wären das a) auch Deine Probleme, also kein absurder Spezialfall,
sondern Dein Arbeitsalltag und b) war das Argument FÜR anonyme
Strukturen, dass man so den Namensraum sauber hält - aber wenn man keine
IDE-Unterstützung hat, dann spielt das m.M. nach eh keine Rolle.
Rufus Τ. F. schrieb:>> Die Lösung wäre, im Zweifel, um garantiert in jeder Hinsicht portabel zu>> sein, nur den kleinsten gemeinsamen Nenner>> Das wäre K&R-C, also C noch vor C89.
Mitnichten. Der Schritt von K&R- zu ANSI-C führte zu wesentlich
verbesserter Portabilität. Die Sprache war davor zu schwach definiert,
was zu inkompatiblen Compilern führte.
Ich würde auch nicht drauf wetten, dass jeder Compiler überhaupt noch
K&R akzeptiert.
Markus K. schrieb:> Das funktioniert leider auch mit guten Namen. Immer wenn man in zwei> verschiedenen Structs members mit dem gleichen Namen benutzt, z.B. weil> damit das selbe gemeint ist.
Aber es ist nur ein Problem, wenn auch die anderen "wenns" erfüllt sind.
Markus K. schrieb:> Die Prämisse in der Diskussion war doch, dass man alle Strukturen anonym> macht. Dann sind auch die geschachtelten Strukturen anonym.
Es ging ursprünglich nur um die struct A_.
Markus K. schrieb:> Dann wären das a) auch Deine Probleme, also kein absurder Spezialfall,> sondern Dein Arbeitsalltag und b) war das Argument FÜR anonyme> Strukturen, dass man so den Namensraum sauber hält - aber wenn man keine> IDE-Unterstützung hat, dann spielt das m.M. nach eh keine Rolle.
Klar wäre es dann auch mein Problem. Aber ich würde das Problem eher
über eins der anderen "wenns" lösen. Ein besserer Compiler kann ein
Problem sein, aber eine bessere IDE?
Markus K. schrieb:> Die Prämisse in der Diskussion war doch, dass man alle Strukturen anonym> macht. Dann sind auch die geschachtelten Strukturen anonym.
Nein. wieso sollten die Anonym sein? Es ging nur um Typedefs.