mikrocontroller.net

Forum: Compiler & IDEs Zugriff auf Struktur


Autor: Jürgen (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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'

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das hier
struct bat {
       uint16_t  U;
       uint16_t  SOC;
       uint16_t  SOH;
          }

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
************
void testfunktion(void)
{
 extern struct bat BAT;

 BAT.U = 2;
}

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.


Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ach ja. Wie macht man sowas richtig:

global.h
********
#ifndef GLOBAL_H
#define GLOBAL_H

struct bat {
       uint16_t  U;
       uint16_t  SOC;
       uint16_t  SOH;
};

extern struct bat BAT;

#endif

main.c
******

#include "global.h"

struct bat BAT;

void testfunktion(void);

int main(void)
{
  U.BAT = 1;

 for(;;)
 {
   testfunktion();
 }
}

test.c
******
#include "global.h"

void testfunktion(void)
{
 BAT.U = 2;
}

  

Autor: Jürgen (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?


Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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)
void testfunktion(void)
{
 extern struct bat BAT;

 BAT.U = 2;
}

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
void testfunktion(void)
{
 extern struct bat BAT;

 BAT.U = 2;
}
kann er das nicht feststellen.


Autor: Frank Jonischkies (frajo)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was ist U.BAT? Habe ich was übersehen? Und die Struktur von Jürgen war 
doch
struct bat {
       uint16_t  U;
       uint16_t  SOC;
       uint16_t  SOH;
          }BAT;
Also mit BAT am Ende.

Autor: Jürgen (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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!


Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Frank Jonischkies wrote:
> Was ist U.BAT? Habe ich was übersehen? Und die Struktur von Jürgen war
> doch
>
struct bat {
>        uint16_t  U;
>        uint16_t  SOC;
>        uint16_t  SOH;
>           }BAT;
> 
> 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
struct bat {
     uint16_t  U;
     uint16_t  SOC;
     uint16_t  SOH;
};

struct bat BAT;

lass dich nicht von den vermeintlich gleichlautenden
Bezeichnungen für die Struktur und den Variablennamen
verwirren.

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Karl Heinz:
Ich glaube, Frank meinte die tatsächlich falsche Zeile im 
Originalprogramm mit der Zuweisung
U.BAT = 1;
(erste Zeile in main). Das muss auf jeden Fall wenn überhaupt dann
BAT.U = 1;
heißen!

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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
struct bat {
    uint16_t  U;
    uint16_t  SOC;
    uint16_t  SOH;
};

extern struct bat BAT;

oder so
extern struct bat {
                   uint16_t  U;
                   uint16_t  SOC;
                   uint16_t  SOH;
                  }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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Frank Jonischkies (frajo)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Jürgen (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jürgen wrote:
>
> Nichts für Ungut

Kein Problem.
Aber jetzt hats 'klick' gemacht?

Autor: Jürgen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja, jetzt erscheint alles völlig logisch :) Ist es eigentlich ja auch, 
wenn man weiß wie der Compiler denkt....

Danke

Jürgen

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]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [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.