Hallo, ich habe ein Problem beim Zugriff auf eine Struktur, vielleicht kann mir jemand weiterhelfen. Ich definiere eine globale Struktur in einem Modul und möchte Sie in einem anderen Modul verwenden. Hier ein kleiner Programmauschnitt, natürlich so nicht kompilierbar, weil ohne includes usw., ausßerdem völlig sinnlos... /********************************************* Modul main.c struct bat { uint16_t U; uint16_t SOC; uint16_t SOH; }BAT; int main(void) { U.BAT = 1; for(;;) { testfunktion(); //in Modul test.c } } /*********************************************** /********************************************* Modul test.c void testfunktion(void) { extern struct bat BAT; BAT.U = 2; } /*********************************************** Kompilieren führt zu folgender Fehlermeldung: ../CanApp.c:49: error: invalid use of undefined type `struct bat'
Das hier
1 | struct bat { |
2 | uint16_t U; |
3 | uint16_t SOC; |
4 | uint16_t SOH; |
5 | }
|
ist zunächst mal nur die Definition eines Datentyps. Ein Datentyp so wie int or char or double.Er heist halt 'struct bat' Nun machst du aber: Modul test.c ************
1 | void testfunktion(void) |
2 | {
|
3 | extern struct bat BAT; |
4 | |
5 | BAT.U = 2; |
6 | }
|
Woher soll denn jetzt der Compiler wissen, wie ein 'struct bat' aufgebaut ist. Denk immer daran: Verschiedene *.c Dateien werden unabhängig voneinander compiliert. Wenn dem Compiler in main.c erzählt wird wie ein 'struct bat' aufgebaut ist, so ist das zwar schön in Bezug auf main.c. Es hat aber keinerlei Auswirkungen auf test.c. Wenn der Compiler sich test.c vornimmt, fängt er (fast) bei 0 an, insbesondere hat er keinerlei Wissen darüber, was sich in main.c getan hat. main.c und test.c werden unabhängig voneinander kompiliert.
Ach ja. Wie macht man sowas richtig: global.h ********
1 | #ifndef GLOBAL_H
|
2 | #define GLOBAL_H
|
3 | |
4 | struct bat { |
5 | uint16_t U; |
6 | uint16_t SOC; |
7 | uint16_t SOH; |
8 | };
|
9 | |
10 | extern struct bat BAT; |
11 | |
12 | #endif
|
main.c ******
1 | #include "global.h" |
2 | |
3 | struct bat BAT; |
4 | |
5 | void testfunktion(void); |
6 | |
7 | int main(void) |
8 | {
|
9 | U.BAT = 1; |
10 | |
11 | for(;;) |
12 | {
|
13 | testfunktion(); |
14 | }
|
15 | }
|
test.c ******
1 | #include "global.h" |
2 | |
3 | void testfunktion(void) |
4 | {
|
5 | BAT.U = 2; |
6 | }
|
Es heißt aber: struct bat { uint16_t U; uint16_t SOC; uint16_t SOH; } BAT; bat ist also der Datentyp und ich habe davon gleich eien Instanz BAT initialisiert. Damit müsste auch extern sturct bat BAT in Modul test.c möglich sein, oder nicht?
Jürgen wrote: > Damit müsste auch extern sturct bat BAT in Modul test.c möglich sein, > oder nicht? Nochmal. In diesem Quellcode (und du darfst nur diesen Quellcode und die C Regeln benutzen, sonst nichts. Kein Umgebungswissen und auch nichts aus main.c)
1 | void testfunktion(void) |
2 | {
|
3 | extern struct bat BAT; |
4 | |
5 | BAT.U = 2; |
6 | }
|
Wie gross ist denn BAT? wieviele Bytes belegt es? Welche Komponenten existieren in BAT? Die Antwort: Du kannst es nicht wissen. Dieses Wissen ist in main.c begraben. Das hier ist aber nicht main.c! Das hier ist test.c! Und hier gilt nur das, was in test.c drinnen steht. Da steht aber nichts darüber, wie die 'struct bat' aufgebaut ist. Das muss der Compiler aber wissen. Er will ja schliesslich prüfen, ob es in struct bat tatsächlich eine Komponente namens 'U' gibt. Auch wäre es für den Compiler ganz gut zu wissen, wo denn in der struct bat diese Komponente angesiedelt ist, das wievielte Byte ab Beginn der Struktur denn das 'U' ist. Aber dem Compiler gehts wie dir. Nur mit diesem Code ausgerüstet
1 | void testfunktion(void) |
2 | {
|
3 | extern struct bat BAT; |
4 | |
5 | BAT.U = 2; |
6 | }
|
kann er das nicht feststellen.
Was ist U.BAT? Habe ich was übersehen? Und die Struktur von Jürgen war doch
1 | struct bat { |
2 | uint16_t U; |
3 | uint16_t SOC; |
4 | uint16_t SOH; |
5 | }BAT; |
Also mit BAT am Ende.
Hmm, ich denke mal, das hier ist richtig: extern struct bat { uint16_t U; uint16_t SOC; uint16_t SOH; }BAT; Damit ist der Aufbau der Struktur auch in test.c vollständig beschrieben. Das kann man dann wohl Hilfe zur Selbsthilfe nennen :) Nicht einfach öde die Lösung hingeschrieben, sondern mich zum Überlegen angeregt. Vielen Dank! Ist mir übrigens schon öfter aufgefallen, dass du hier wohl einer der großen Peiler bist!
Frank Jonischkies wrote: > Was ist U.BAT? Habe ich was übersehen? Und die Struktur von Jürgen war > doch >
1 | struct bat { |
2 | > uint16_t U; |
3 | > uint16_t SOC; |
4 | > uint16_t SOH; |
5 | > }BAT; |
6 | >
|
> Also mit BAT am Ende.
Das sind 2 Dinge in einem
* zum einen wird der Datentyp struct bat definiert
* zum anderen wird auch gleich noch eine Variable von diesem
Typ angelegt.
Das ganze ist also die kürzere Schreibweise von
1 | struct bat { |
2 | uint16_t U; |
3 | uint16_t SOC; |
4 | uint16_t SOH; |
5 | };
|
6 | |
7 | struct bat BAT; |
lass dich nicht von den vermeintlich gleichlautenden Bezeichnungen für die Struktur und den Variablennamen verwirren.
@Karl Heinz: Ich glaube, Frank meinte die tatsächlich falsche Zeile im Originalprogramm mit der Zuweisung
1 | U.BAT = 1; |
(erste Zeile in main). Das muss auf jeden Fall wenn überhaupt dann
1 | BAT.U = 1; |
heißen!
Jürgen wrote: > Hmm, ich denke mal, das hier ist richtig: > > extern struct bat { > uint16_t U; > uint16_t SOC; > uint16_t SOH; > }BAT; > > Damit ist der Aufbau der Struktur auch in test.c vollständig > beschrieben. spielst du jetzt auf das von mir neu eingeführte File global.h an? Wenn ja: Ganz genau Ob du das so
1 | struct bat { |
2 | uint16_t U; |
3 | uint16_t SOC; |
4 | uint16_t SOH; |
5 | };
|
6 | |
7 | extern struct bat BAT; |
oder so
1 | extern struct bat { |
2 | uint16_t U; |
3 | uint16_t SOC; |
4 | uint16_t SOH; |
5 | }BAT; |
schreibst, ist gehupft wie gesprungen. Beides ist identisch. Persönlich bevorzuge ich die erste Variante, weil ich da besser sehe, was denn Datentyp-Definition ist, und was Variablendeklaration. Für den Compiler macht das aber keinen Unterschied. > Das kann man dann wohl Hilfe zur Selbsthilfe nennen :) Nicht einfach öde > die Lösung hingeschrieben, sondern mich zum Überlegen angeregt. Davon hast du vielmehr, als wenn ich einfach nur korrigiere. Gib einem Mann einen Fisch und er hat einmal zu essen. Lehre ihn wie man fischt und er hat immer zu essen. > Ist mir übrigens schon öfter aufgefallen, dass du hier wohl einer der > großen Peiler bist! Na ja. Nach 20 Jahren C Programmierung, sollte doch schon einiges hängen geblieben sein.
Johannes M. wrote: > @Karl Heinz: > Ich glaube, Frank meinte die tatsächlich falsche Zeile im > Originalprogramm mit der Zuweisung Ja klar. Hab ich übersehen. Das war ja auch nicht das Problem an sich.
Karl heinz Buchegger wrote:
> * zum einen wird der Datentyp struct bat definiert
Muß man da nicht typedef nehmen? Oder ist es hier nicht erforderlich.
> Muß man da nicht typedef nehmen?
Muss man nicht. Er schrieb ja nicht, dass der Datentyp "bat" definiert
würde, sondern "struct bat". Mit einem typedef kann man diesem dann
noch einen Kurznamen ohne "struct" geben. In C++ ist die Qualifikation
mit "struct" nicht notwendig, dort definiert "struct foo" auch immer
einen Typnamen "foo" zugleich mit, im gleichen Scope.
@Karl heinz Buchegger: Hmm, zwischenzeitlich habe ich wohl einige blöde Kommentare geschrieben. Irgendwie habe ich die einzelnen Antworten hier nicht in der richtigen zeitlichen Abfolge gesehen, wieso auch immer. Ich habe den Beitrag mit global.h erst sehr viel später gesehen, deswegen mein sinnloser Kommentar zwischendurch... Nichts für Ungut Jürgen
Jürgen wrote: > > Nichts für Ungut Kein Problem. Aber jetzt hats 'klick' gemacht?
Ja, jetzt erscheint alles völlig logisch :) Ist es eigentlich ja auch, wenn man weiß wie der Compiler denkt.... Danke Jürgen
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.