Forum: Compiler & IDEs Include -> Variable undeclared, troz define


von lightninglord (Gast)


Angehängte Dateien:

Lesenswert?

Hallo
ich habe ein kleine Problem mit dem beigefügeten Code:

Ich habe meine Code etwas zerlegt um etwas mehr übersicht reinzubringen 
( wird noch größer ), also hab ich einfach nen paar Routinen und 
Definitionen in xxx.c gepackt und dann im Main.c per Include eingefügt, 
das hat auch ganz toll funktioniert, bis ich im main die Variable ( 
union ) Anzeige definiert hab und diese auch in einer Includierten .c 
verwende dann bekomme ich dies Fehlermeldung:

../SPI.c:53: error: 'Anzeige' undeclared (first use in this function)
../SPI.c:53: error: (Each undeclared identifier is reported only once
../SPI.c:53: error: for each function it appears in.)

Wenn ich nun die Funktion in die Main packe gehts, aber nicht wenn sie 
inner seperaten .c liegt? Wo bitte liegt den mein Fehler?

PS: Ich verwende WinAVR 20070525 und AVR Studio 4

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Aus dem Quelltextfile mit main():
1
#include <avr/io.h>
2
3
#include "USART.c"
4
#include "SPI.c"
5
6
union{
7
8
  unsigned short all;                    // 16-Bit Anzeige ( SPI-Daten )
9
  unsigned char byte[2];                  // High- und Low-Byte
10
11
}Anzeige;
12
...

Wenn der Compiler USART.c und SPI.c am bearbeiten ist, hat er dann die 
Definition der union schon gesehen? Ich denke nein. Logisch dass da ein 
Fehler gemeldet wird.

Das Includen von C-Dateien macht man üblicherweise nicht. Das sinnvolle 
Auslagern von Funktionen ist in der Artikelsammlung beschrieben:
http://www.mikrocontroller.net/articles/Funktionen_auslagern_%28C%29

von lightninglord (Gast)


Lesenswert?

Vielen Danke. Das mit den .h hab ich nicht gewusst, bin noch bissle neu 
in C ;-). Jetzt müsste ichs aber schon hinbekommen
Nochmal Danke.

von lightninglord (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,
ich habs doch leider nicht geschafft, irgenwo hat sich ne Fehlerlein 
eingeschlcieh aber ich finds einfach nicht. Wenn ich Compiliere dann 
bekomme ich immer ne Fehlermeldung inner .h :

../SPI.h:23: error: expected '=', ',', ';', 'asm' or '__attribute__' 
before 'Anzeige'

naja und ich weis einfach nicht wieso ich meinen eigenen Variablentyp
1
typedef union {
2
  
3
  unsigned short all;
4
  
5
  struct {
6
    
7
    unsigned char low;
8
    unsigned char high;
9
    
10
  };
11
12
} short2bytes;
13
14
short2bytes Anzeige;

nicht  mit
1
extern short2bytes Anzeige;

in meine ausgelagerte .c bekomme. Könnt ihr mir bitte nochmal helfen, 
bin fast am verzweifeln.

von Uhu U. (uhu)


Lesenswert?

.c-Files zieht man üblicherweise nicht mit #include in einen .c-File 
rein.

.c-Files sind Moduldateien, die .h* includen. Das fertige Programm baut 
dann der Linker aus dem zusammen, was der Compiler aus .c gemacht hat.

von Stefan B. (stefan) Benutzerseite


Angehängte Dateien:

Lesenswert?

Ist wahrscheinlich ein Folgefehler der seltsamen Funktionsprototypen. 
Ich würde das Projekt anders aufziehen.

Becc*.c = Hauptsource

Becc*.h = Hauptinclude, darin alle vom User anpassbaren Defines zur 
Konfiguration (F_CPU, BAUD) + alle Typedefs + alle exteren 
Variablendeklarationen + alle Includes (avr/io.h + SPI.h + USART.h). 
Wird in jedem Modul includiert.

SPI.c = Routinen SPI
SPI.h = Prototypen Routinen SPI
USART.c = Routinen USART
USART.h = Prototypen Routinen USART

von Karl H. (kbuchegg)


Lesenswert?

lightninglord wrote:
>
>
1
extern short2bytes Anzeige;
>
> in meine ausgelagerte .c bekomme. Könnt ihr mir bitte nochmal helfen,
> bin fast am verzweifeln.

Du musst dir immer eines vergegenwärtigen.

Wenn er Compiler eine *.c Datei compiliert, dann kennt er nur
diese eine Datei. Es ist völlig unerheblich, was in anderen
*.c Dateien steht, es wird nur das berücksichtigt was in dieser
einen Datei steht. C kennt keinen Projektgedanken wie ihn andere
Sprachen haben.

Der Compiler geht deinen Code von oben nach unten durch. Alles
was verwendet wird, muss vor der Verwendung definiert werden.

Wenn der Compiler short2bytes nicht kennt, dann deshalb, weil
es nicht vor der Verwendung in diesem .c File* definiert
wurde. Es ist völlig unerheblich, ob diese union in einer anderen
*.c definiert ist. Der Compiler compiliert jetzt dieses File
und nur der Inhalt dieses Files wird untersucht.

Daher werden solche unions oder Strukturen auch in Header Files
ausgelagert, damit man immer die gleiche Strukturdefinition in
das jeweilige *.c File inkludieren kann. Inkludieren ist genauso-
gut, wie wenn du das direkt hingeschrieben hättest. Im Grunde
passiert eigentlich sogar genau das: Der Quelltext den du geschrieben
hast, wird vor dem eigentlichen compilieren nochmal modifiziert.
Genauso wie du es mit deinem Texteditor machen würdest, wenn du
die #include Zeile mit dem Inhalt der angegebenen Datei ersetzt.

Also machst du dir erst mal ein Header File, in dem alles notwendige
enthalten ist. Dazu gehört selbstverständlich auch die Definition
deiner Struktur

Definition.h
************
1
typedef union {
2
  
3
  unsigned short all;
4
  
5
  struct {
6
    
7
    unsigned char low;
8
    unsigned char high;
9
    
10
  };
11
12
} short2bytes;
13
14
extern short2bytes Anzeige;

Dieses Header File ist für sich alleine genommen vollständig.
Eine Variable 'Anzeige' wird deklariert (extern, dazu gleich später
mehr), und auch was es mit dem Datentyp short2bytes auf sich hat
ist da drinn enthalten.

Das heist, wenn du dieses Header File irgendwo inkludierst, dann
bringt dieses Header File alles mit, was gebraucht wird um die
Deklaration von 'Anzeige' machen zu können.

zb.

Test1.c
*******
1
#include "Definition.h"
2
3
void Funktion1()
4
{
5
  Anzeige.all = 5;
6
}

Wenn der Compiler dieses Test.c übersetzt, dann kommt zuerst der
Preprozessor zum Zug, der die include Zeile mit dem Inhalt der
Datei Definition.h ersetzt. Das Ergebnis ist dann
1
typedef union {
2
  
3
  unsigned short all;
4
  
5
  struct {
6
    
7
    unsigned char low;
8
    unsigned char high;
9
    
10
  };
11
12
} short2bytes;
13
14
extern short2bytes Anzeige;
15
16
void Funktion1()
17
{
18
  Anzeige.all = 5;
19
}
20
[C]
21
22
Wie du dich überzeugen kannst, ist jetzt in dieser Compiliereinheit
23
alles enthalten, was der Compiler braucht um sie übersetzten zu
24
können. Nichts ist undefiniert. Von jedem Nicht-C-Schlüsselwort,
25
insbesondere von der union gibt es eine Definition und wenn man
26
diese Übersetzungseinheit ansieht und von oben nach unten durchliest,
27
dann wird alles erklärt (definiert) bevor es verwendet wird.
28
29
Nun kommt aber im Header File, und damit auch in jeder Übersetzungs-
30
einheit die dieses includiert, eine Variable
31
[C]
32
extern short2bytes Anzahl;
vor. Das 'extern' bedeutet an dieser Stelle einfach nur: Diese
Variable existiert irgendwo. Wo genau ist an dieser Stelle nicht
wichtig. Es reicht, dass der Compiler weiss, dass es sie gibt und
dass daher die Verwendung einer Variablen 'Anzahl' kein Tippfehler
ist sondern dass es diese Variable tatsächlich irgendwo gibt.

Nur: Irgendwo muss es diese Variable dann aber auch tatsächlich
geben. In einem, und nur in einem, *.c File muss diese Variable
auch tatsächlich angelegt werden. Nun, meistens macht man das
in dem *.c File, in dem auch main() ist. Das ist aber nur eine
Konvention, dass muss nicht unbedingt so sein.
Aber lass uns das mal so machen.
Damit die Variable auch tatsächlich erzeugt werden kann, muss
natürlich der Datentyp short2bytes an der Stelle der Variablen-
definition bekannt sein. Wo kriegen wir den her? Na, ganz einfach.
Indem 'Definitionen.h' inkludiert wird, denn dort steht ja die
Definition dieses Datentyps drinnen

main.c
******
1
#include "Definitionen.h"
2
3
short2bytes Anzeige;
4
5
int main()
6
{
7
  Anzeige = 5;
8
}

Auch hier wieder. Bevor sich der Compiler diesen Quelltext vornimmt
kommt erst mal der Preprozessor zum Zug, der den include durch
den Inhalt der Datei ersetzt. Aus deinem Quelltext wird so
als Zwischenstufe:
1
typedef union {
2
  
3
  unsigned short all;
4
  
5
  struct {
6
    
7
    unsigned char low;
8
    unsigned char high;
9
    
10
  };
11
12
} short2bytes;
13
14
extern short2bytes Anzeige;
15
16
short2bytes Anzeige;
17
18
int main()
19
{
20
  Anzeige = 5;
21
}

Und auch hier wieder: Wenn du das Programm von oben nach unten
durchgehst, ist alles vor seiner Verwendung definiert worden.
Dass es hier die Sequenz gibt
1
extern short2bytes Anzeige;
2
3
short2bytes Anzeige;
mag zwar auf den ersten Blick seltsam aussehen, stört aber nicht
weiter. Die erste Zeile (die mit dem extern) ist eine Deklaration
und sagt als solches aus: Irgendwo gibt es ... Die zweite Zeile
hingegen sagt umgangssprachlich aus: Und hier ist sie!

von lightninglord (Gast)


Lesenswert?

Vielend Dank, ihr habt mir ja wunderbar geholfen, habs jetzt endlich ml 
so richtig verstanden was die .h-Files zu bedeuten haben und wie man 
damit umgehen sollte. Vielen Dank , werd mein Projekt mla gleich 
dementsprechend ändern dann musste es an Pfirsich auch funktionieren.

Grüßle lightninglord


PS: Mir gefällts bei euch richtig gut, da werde ich mich gleich mal 
registrieren.

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.