Forum: Compiler & IDEs Struct extern deklarieren?


von Irosenhagen (Gast)


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?

von Johannes M. (johnny-m)


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?

von Oliver (Gast)


Lesenswert?

Ein Blick ins C-Buch hilft eventuell weiter.

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

oder im header file:
1
typedef struct
2
{int a, b}
3
RTC_Para_typ;
4
5
extern RTC_Para_typ RTC_Para_tag;
und im C-File;
1
RTC_Para_typ RTC_Para_tag;

Oliver

von Oliver (Gast)


Lesenswert?

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

Oliver

von Karl H. (kbuchegg)


Lesenswert?

Oliver wrote:
> Ein Blick ins C-Buch hilft eventuell weiter.
>
> Entweder im C-File
>
1
> struct RTC_Para_typ
2
> {int a, b}
3
> 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:
>
1
> typedef struct
2
> {int a, b;}
3
> RTC_Para_typ;
4
> 
5
> extern RTC_Para_typ RTC_Para_tag;
6
>
> und im C-File;
>
1
> RTC_Para_typ RTC_Para_tag;
2
>

So rum gehts.

von Oliver (Gast)


Lesenswert?

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

Also nochmal Variante 1:

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

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

in B.c:
1
#include "A.h"
2
3
int main()
4
{
5
   RTC_Para_tag.a = 0;
6
}

Oliver

von Irosenhagen (Gast)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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

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
1
  struct RTC_Para_typ
2
  {double c;
3
   int a, b;}
4
  RTC_Para_tag;
5
6
void foo()
7
{
8
  RTC_Para_tag.c = 5.2345E12;
9
  RTC_Para_tag.b = 128;
10
}

A.h
1
extern struct RTC_Para_typ
2
{int a, b}
3
RTC_Para_tag; 
4
5
void foo();

und dann in main()
1
#include "A.h"
2
3
int main()
4
{
5
   RTC_Para_tag.a = 0;
6
   foo();
7
8
   // und hier siehst du dir mal RTC_Para_tag.a an und wunderst
9
   // dich, warum das nicht mehr 0 ist.
10
}

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
1
struct RTC_Para_typ
2
{ double c;
3
  int a, b;
4
};
5
6
extern struct RTC_Para_typ RTC_Para_tag; 
7
void foo();

A.c
1
#include "A.h"
2
struct RTC_Para_typ RTC_Para_tag;
3
4
void foo()
5
{
6
  RTC_Para_tag.c = 5.2345E12;
7
  RTC_Para_tag.b = 128;
8
}
1
#include "A.h"
2
3
int main()
4
{
5
   RTC_Para_tag.a = 0;
6
   foo();
7
}

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

von Oliver (Gast)


Lesenswert?

>Das ist doch Unsinn.

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

Oliver

von Thomas S. (thomass)


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
1
//   ...
2
struct Timer
3
{
4
  uint8_t zahl
5
};
6
extern struct Timer AlleTimer[16];
7
//   ...

Timer.c
1
#include <avr/io.h>
2
#include <Timer.h>
3
void StartTimer (uint8_t nr, uint8_t wert
4
{
5
  if(nr < Nr_Timer)
6
  {
7
  AlleTimer[nr].zahl = wert;
8
  }
9
}

main.c
1
#include <avr/interrupt.h>
2
#include <avr/io.h>
3
#include <avr/Timer.h>
4
// .......
5
ISR (...........)
6
{
7
  uint8_t i;
8
  for(i=0;i<Nr_Timer;i++)
9
  {
10
    if(AlleTimer(i).wert > 0)
11
      AlleTimer(i).wert--;
12
  }
13
}

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

Gruss

Thomas

von Robert B. (goldcap) Benutzerseite


Lesenswert?

Hallo,

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

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

Versuchs damit, ein Element ist "struct Timer" und kein Pointer.
1
#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
1
struct Timer
2
{
3
  uint8_t zahl
4
};
5
extern struct Timer AlleTimer[]; 
6
extern uint8_t sizeof_AlleTimer(void);
7
#define NrTimer (sizeof_AlleTimer()/sizeof(struct Timer));

t.c
1
#include "t.h"
2
struct Timer AlleTimer[] = {
3
  {0,},
4
  {1,},
5
#if NEED_TWO
6
  {2,},
7
#endif
8
  {3,},
9
  {4,},
10
}
11
12
uint8_t sizeof_AlleTimer(void)
13
{
14
  return sizeof(AlleTimer);
15
}

main.c
1
#include "t.h"
2
3
uint8_t c;
4
5
main()
6
{
7
  for(c=0;c<NrTimer;c++) {
8
...
9
  }
10
}
11
[c]
12
13
damit werden auch dynamisch allokierte oder per Praeprozessor selektierte structs korrekt in der Grösse behandelt.
14
15
In deinem Fall könntest du aber auch im .h file folgendes schreiben,
16
da du ja die Grösse auf jeden Fall vordefinierst.
17
[c]
18
#define NrTimer 16
19
struct Timer
20
{
21
  uint8_t zahl
22
};
23
extern struct Timer AlleTimer[NrTimer];

damit würde die Berechnung einfach entfallen.

von Robert B. (goldcap) Benutzerseite


Lesenswert?

noch ein Nachtrag,

nachdem AlleTimer in einer Interruptroutine verändert wird sollte die 
Deklaration ausserdem als volatile erfolgen. Sonst wird der Compiler
das
1
if(AlleTimer(i).wert > 0)
2
  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.

von Karl H. (kbuchegg)


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

von Karl H. (kbuchegg)


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
>
1
> if(AlleTimer(i).wert > 0)
2
>   AlleTimer(i).wert--;
3
>
> 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.

von Karl H. (kbuchegg)


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.
1
#define NR_TIMER (sizeof(AllTimer) / (sizeof(*AllTimer)))

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.