Forum: Compiler & IDEs Zugriff auf Struktur


von Jürgen (Gast)


Lesenswert?

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'

von Karl H. (kbuchegg)


Lesenswert?

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.


von Karl H. (kbuchegg)


Lesenswert?

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
}

  

von Jürgen (Gast)


Lesenswert?

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?


von Karl H. (kbuchegg)


Lesenswert?

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.


von Frank J. (frajo)


Lesenswert?

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.

von Jürgen (Gast)


Lesenswert?

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!


von Karl H. (kbuchegg)


Lesenswert?

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.

von Johannes M. (johnny-m)


Lesenswert?

@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!

von Karl H. (kbuchegg)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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.

von Frank J. (frajo)


Lesenswert?

Karl heinz Buchegger wrote:
> * zum einen wird der Datentyp struct bat definiert
Muß man da nicht typedef nehmen? Oder ist es hier nicht erforderlich.

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


Lesenswert?

> 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.

von Jürgen (Gast)


Lesenswert?

@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

von Karl H. (kbuchegg)


Lesenswert?

Jürgen wrote:
>
> Nichts für Ungut

Kein Problem.
Aber jetzt hats 'klick' gemacht?

von Jürgen (Gast)


Lesenswert?

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
Noch kein Account? Hier anmelden.