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'
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
voidtestfunktion(void)
2
{
3
externstructbatBAT;
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.
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
voidtestfunktion(void)
2
{
3
externstructbatBAT;
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
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
structbat{
2
>uint16_tU;
3
>uint16_tSOC;
4
>uint16_tSOH;
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
structbat{
2
uint16_tU;
3
uint16_tSOC;
4
uint16_tSOH;
5
};
6
7
structbatBAT;
lass dich nicht von den vermeintlich gleichlautenden
Bezeichnungen für die Struktur und den Variablennamen
verwirren.
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
structbat{
2
uint16_tU;
3
uint16_tSOC;
4
uint16_tSOH;
5
};
6
7
externstructbatBAT;
oder so
1
externstructbat{
2
uint16_tU;
3
uint16_tSOC;
4
uint16_tSOH;
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.
> 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