mikrocontroller.net

Forum: Compiler & IDEs Struct extern deklarieren?


Autor: Irosenhagen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hey, ich hänge gerade fest. Und zwar möchte ich das RTC-Programm von 
hier:
Beitrag "Real Time Clock mit RTC4513 EPSON" in mein Programm einbinden.

In dem Programm werden die Daten für die Zeit&Datum in eine Struct 
gepackt:

typedef struct RTC_Para_tag
  {
  unsigned char Second;
  unsigned char Minute;
  unsigned char Hour;
  unsigned char Day;
  unsigned char Month;
  unsigned char Year;     // without 2000
  unsigned char DayOfWeek;  // {1-7}
  } RTC_Para_typ;

In meinem Hauptprogramm hab ich jetzt zunächst die passende include 
eingefügt:

#include <time.h>

Danach hab ich die struct extern deklariert:

extern struct RTC_Para_typ RTC_Para_tag;

Im Programm selbst will ich jetzt der Struct Werte zuweisen. Mein 
Programm liest über Tasten Werte für die Variablen Minute,Stunde,Tag und 
Monat aus.

Also hab ich nun einfach probiert über:

  RTC_Para_tag.Second    = 0;
  RTC_Para_tag.Minute    = Minutes;
  RTC_Para_tag.Hour    = Hours;
  RTC_Para_tag.Day    = Day;
  RTC_Para_tag.Month    = Month;
  RTC_Para_tag.Year    = 08;

Werte in die Struct zu speichern. Aber entweder ist der Aufruf falsch 
oder ich hab bei der Deklaration etwas übersehen. Fehlermeldung ist:

error: invalid use of undefined type 'struct RTC_Para_typ'

Und das für jede Zeile der Zuweisung.
Hat jemand nen Tipp?

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

Bewertung
0 lesenswert
nicht lesenswert
Das "struct" bei der Deklaration ist zu viel, das steckt doch schon im 
typedef mit drin. Außerdem: Gibt es einen triftigen Grund für das 
"extern"? Ist die Variable in einem anderen Modul definiert?

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ein Blick ins C-Buch hilft eventuell weiter.

Entweder im C-File
struct RTC_Para_typ
{int a, b}
RTC_Para_tag;
und im header file das alle nochmal, mit "extern" davor,

oder im header file:
typedef struct
{int a, b}
RTC_Para_typ;

extern RTC_Para_typ RTC_Para_tag;
und im C-File;
RTC_Para_typ RTC_Para_tag;

Oliver

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
... und mit einem Semikolon nach dem b gehts noch besser :-)
{int a, b;}

Oliver

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

Bewertung
0 lesenswert
nicht lesenswert
Oliver wrote:
> Ein Blick ins C-Buch hilft eventuell weiter.
>
> Entweder im C-File
>
> struct RTC_Para_typ
> {int a, b}
> RTC_Para_tag;
> und im header file das alle nochmal, mit "extern" davor,

Das bringt dich aber nicht wirklich weiter.
Das führt nämlich dann genau zu der beobachteten Fehlermeldung:

invalid use of undefined type 'struct RTC_Para_typ'


Wenn du im C File A.c die Struktur definierst und das besagte
Header File in B.c inkludierst, wie soll dann der Compiler in B.c
wissen, wie die Struktur aussieht?

> oder im header file:
>
> typedef struct
> {int a, b;}
> RTC_Para_typ;
> 
> extern RTC_Para_typ RTC_Para_tag;
> 
> und im C-File;
>
> RTC_Para_typ RTC_Para_tag;
> 

So rum gehts.

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es geht schon beides, aber vielleicht habe ich mich unglücklich 
ausgedrückt:

Also nochmal Variante 1:

in A.c:
struct RTC_Para_typ
{int a, b}
RTC_Para_tag; 

in A.h nochmal alles, mit extern davor:
extern struct RTC_Para_typ
{int a, b}
RTC_Para_tag; 

in B.c:
#include "A.h"

int main()
{
   RTC_Para_tag.a = 0;
}

Oliver

Autor: Irosenhagen (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Alles Klar, hatte gerade keine brauchbare Lektüre zur Hand.
Danke für die Hilfe!

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

Bewertung
0 lesenswert
nicht lesenswert
Oliver wrote:
> Es geht schon beides, aber vielleicht habe ich mich unglücklich
> ausgedrückt:
>
> Also nochmal Variante 1:
>
> in A.c:
>
> struct RTC_Para_typ
> {int a, b}
> RTC_Para_tag;
> 
>
> in A.h nochmal alles, mit extern davor:
>
> extern struct RTC_Para_typ
> {int a, b}
> RTC_Para_tag;
> 

Das ist doch Unsinn.
Ich werde doch nicht die Strukturdekleration hier
nochmal wiederholen. Einmal reicht völlig.
Da besteht dann auch keine Gefahr, dass die beiden
Deklerationen auseinanderlaufen.

Du kannst ja mal probehalber folgendes ausprobieren

A.c
  struct RTC_Para_typ
  {double c;
   int a, b;}
  RTC_Para_tag;

void foo()
{
  RTC_Para_tag.c = 5.2345E12;
  RTC_Para_tag.b = 128;
}

A.h
extern struct RTC_Para_typ
{int a, b}
RTC_Para_tag; 

void foo();

und dann in main()
#include "A.h"

int main()
{
   RTC_Para_tag.a = 0;
   foo();

   // und hier siehst du dir mal RTC_Para_tag.a an und wunderst
   // dich, warum das nicht mehr 0 ist.
}

Man beachte, dass die Strukturdekleration in A.h nicht mit der
in A.c übereinstimmt. Da A.c den A.h nicht inkludiert (muss sie
auch nicht), entdeckt kein Compiler und kein Linker dieses
Problem. Trotzdem geschehen seltsame Dinge im Programm.

-> Strukturdeklarationen immer nur 1 mal machen.
Muss die Deklaration in mehreren Files sichtbar sein, dann
kommt sie in ein Header File.
Und da es sich dabei sowieso immer um eine Deklaration handelt,
ist auch kein extern dafür notwendig:

A.h
struct RTC_Para_typ
{ double c;
  int a, b;
};

extern struct RTC_Para_typ RTC_Para_tag; 
void foo();

A.c
#include "A.h"
struct RTC_Para_typ RTC_Para_tag;

void foo()
{
  RTC_Para_tag.c = 5.2345E12;
  RTC_Para_tag.b = 128;
}
#include "A.h"

int main()
{
   RTC_Para_tag.a = 0;
   foo();
}

Auf die Art kann dir nichts passieren. Egal welchen Fehler
du machst, der Compiler wird ihn entdecken.

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Das ist doch Unsinn.

Einverstanden:-)  Aber es ist zumindest formell richtiger Unsinn.

Oliver

Autor: Thomas S. (thomass)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hey,

der Thread ist zwar schon alt jedoch passt er daher will ich keinen 
neuen aufmachen.
Ich habe ebenfalls 2 Strukturen die ich in ein H-File packen will jedoch 
meckert der Compiler und ich weis nicht warum
Ich habe folgendes Programmiert.

Timer.h
//   ...
struct Timer
{
  uint8_t zahl
};
extern struct Timer AlleTimer[16];
//   ...

Timer.c
#include <avr/io.h>
#include <Timer.h>
void StartTimer (uint8_t nr, uint8_t wert
{
  if(nr < Nr_Timer)
  {
  AlleTimer[nr].zahl = wert;
  }
}

main.c
#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/Timer.h>
// .......
ISR (...........)
{
  uint8_t i;
  for(i=0;i<Nr_Timer;i++)
  {
    if(AlleTimer(i).wert > 0)
      AlleTimer(i).wert--;
  }
}

Die Grösse von Nr_Timer wollte ich wie folgt definieren
#define Nr_Timer (sizeof (AllTimer) / (sizeof ( *AllTimer )))
Ich komme einfach nicht drauf wo/wie ich dieses define schreiben soll.

Gruss

Thomas

Autor: Robert B. (goldcap) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

in main.c
sehe ich nicht dein Timer.h sondern nur das avr/Timer.h

Thomas S. schrieb:
>
> main.c
>
>
> #include <avr/interrupt.h>
> #include <avr/io.h>
> #include <avr/Timer.h>
> // .......
> ISR (...........)
> {
>   uint8_t i;
>   for(i=0;i<Nr_Timer;i++)
>   {
>     if(AlleTimer(i).wert > 0)
>       AlleTimer(i).wert--;
>   }
> }
> 
>
> Die Grösse von Nr_Timer wollte ich wie folgt definieren
>
> #define Nr_Timer (sizeof (AllTimer) / (sizeof ( *AllTimer )))
> 
> Ich komme einfach nicht drauf wo/wie ich dieses define schreiben soll.

Versuchs damit, ein Element ist "struct Timer" und kein Pointer.
#define Nr_Timer (sizeof(AllTimer) / (sizeof(struct Timer)))

Das ganze funktioniert nur wenn das array eine feste grösse hat, hier 
16.
Bei einer Definition eines Arrays of structs ohne Arraygrösse
sieht das ganze anders aus, dann muss man in dem C-File in dem
das struct definiert wird eine Hilfsfunktion haben.
Da der Compiler die Grösse eines structs das in einem anderen C-File 
definiert ist nicht ermitteln kann

z.B.:
t.h
struct Timer
{
  uint8_t zahl
};
extern struct Timer AlleTimer[]; 
extern uint8_t sizeof_AlleTimer(void);
#define NrTimer (sizeof_AlleTimer()/sizeof(struct Timer));

t.c
#include "t.h"
struct Timer AlleTimer[] = {
  {0,},
  {1,},
#if NEED_TWO
  {2,},
#endif
  {3,},
  {4,},
}

uint8_t sizeof_AlleTimer(void)
{
  return sizeof(AlleTimer);
}

main.c
#include "t.h"

uint8_t c;

main()
{
  for(c=0;c<NrTimer;c++) {
...
  }
}
[c]

damit werden auch dynamisch allokierte oder per Praeprozessor selektierte structs korrekt in der Grösse behandelt.

In deinem Fall könntest du aber auch im .h file folgendes schreiben,
da du ja die Grösse auf jeden Fall vordefinierst.
[c]
#define NrTimer 16
struct Timer
{
  uint8_t zahl
};
extern struct Timer AlleTimer[NrTimer];

damit würde die Berechnung einfach entfallen.

Autor: Robert B. (goldcap) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
noch ein Nachtrag,

nachdem AlleTimer in einer Interruptroutine verändert wird sollte die 
Deklaration ausserdem als volatile erfolgen. Sonst wird der Compiler
das
if(AlleTimer(i).wert > 0)
  AlleTimer(i).wert--;
einfach mal wegoptimieren, da es in der ISR nicht weiterverwendet wird.
Ggf optimiert er gleich alles in der ISR weg, da darin offensichtlich
nichts passiert was hinterher noch verwendet wird.

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

Bewertung
0 lesenswert
nicht lesenswert
Robert B. schrieb:

> Versuchs damit, ein Element ist "struct Timer" und kein Pointer.

Das ist auch kein Pointer dort im sizeof.

AllTimer degeneriert hier zur Startadresse des Arrays und diese 
derferenziert ergibt das erste Element. Der sizeof bestimmt also die 
Bytegröße des ersten Elements des Arrays
#define Nr_Timer (sizeof(AllTimer) / (sizeof(*AllTimer)))

ist schon richtig und tatsächlich besser, weil man den Datentyp vom 
AllTimer aus dem #define raushält. OK, bei einer struct ist das eher 
unwahrscheinlich, aber es soll schon vorgekommen sein, dass jemand ein 
int Arrays von int auf long umdefiniert hat und auf den sizeof im Makro 
vergessen hat.

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

Bewertung
0 lesenswert
nicht lesenswert
Robert B. schrieb:
> noch ein Nachtrag,
>
> nachdem AlleTimer in einer Interruptroutine verändert wird sollte die
> Deklaration ausserdem als volatile erfolgen.

Ist bei derartigen Variablen eine gute Idee, ...

> Sonst wird der Compiler
> das
>
> if(AlleTimer(i).wert > 0)
>   AlleTimer(i).wert--;
> 
> einfach mal wegoptimieren, da es in der ISR nicht weiterverwendet wird.

.... das jedoch ist Unsinn. Da AlleTimer eine globale Variable ist, kann 
er das nicht einfach wegoptimieren.

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

Bewertung
0 lesenswert
nicht lesenswert
> meckert der Compiler und ich weis nicht warum

Der erste Schritt ist immer: 'Die Fehlermeldung lesen' und nachdenken 
was damit gemeint sein könnte. Die Fehlermeldung ist zwar nicht immer 
ein hilfreicher Hinweis aber meistens ist sie das.

> Ich komme einfach nicht drauf wo/wie ich dieses define schreiben soll.

In das Headerfile. Denn schliesslich benötigen die Arraygröße ja so gut 
wie alle Funktionen, die auf das Array als Ganzes zugreifen.

Und gewöhn dir bitte an, dass #define Makros komplett in Grossbuchstaben 
geschrieben werden. Das ist zwar nur eine Konvention, aber 
seltsamerweise eine an die sich alle C-Programmierer halten. Man erkennt 
dann viel leichter im Quellcode ob man es mit einem Makro oder mit einer 
Variablen zu tun hat. Da Makros manchmal Fallen beeinhalten können, ist 
es gut, wenn man sie sofort erkennen kann.
#define NR_TIMER (sizeof(AllTimer) / (sizeof(*AllTimer)))

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.