Hallo,
ich habe eine C-Datei: init.c
Dort stehen Funktionen drin, die ich in main() brauche.
Diese Funktionen sind in der init.h deklariert.
In der init.h stehen aber auch Variablen die initialisiert sind und in
den Funktionen benötigt werden.
In der Haupt-C-Datei binde ich die init.h, wie folgt ein #include
"init.h".
In Main() rufe ich die Funktionen auf.
Der Linker meldet mir aber nach dem Compilieren "Multiple definition" !
Also jede Variable soll mehrfach definert worden sein, aber wo ?
Klarquelltext
init.h
------
int g[2]={0,1};
init.c
------
#include "init.h"
void g_f(void)
{
a=g[1];
b=g[2];
}
main.c
------
#include "init.h"
main()
{
g_f();
}
Da meckert der Linker, dass g[] mehrfach definiert ist und zuerst in der
main() Datei.
Wie kann man das umgehen ?
Welches Schlüsselwort muss ich benutzen, um g[] in main() ebenfalls
verändern zu können. Diese Variable soll also global für alle C-Dateien
der Projektes sein !
Ich habe bisher immer alles in ein File programmiert.
Nun soll das anders werden.
Vielleicht kann mir jemand helfen.
In eine .h-Datei gehören nur Deklarationen und keine Definitionen !
Die Definition von g_f() gehört in genau eine .c-Datei, in die
.h-Datei kommt nur der Funktionsprototyp (also besagte Deklaration ).
Damit es klar wird, was ich meine:
1
voidg_f(void)
2
{
3
a=g[1];
4
b=g[2];
5
}
ist eine Definition während
1
voidg_f(void);
die entsprechende Deklaration ist. Wenn Du in der Headerdatei die
Definition unterbringst und die Datei mehr als einmal einbindest, dann
ist die Funktion mit jedem entsprechenden #include definiert, was
unzulässig ist. Generell muss eine Funktion/Variable in einem Projekt
genau einmal definiert sein, während sie beliebig oft deklariert
werden kann. Bei Variablen benutzt man das Schlüsselwort extern um
darauf hinzuweisen, dass es sich um eine Deklaration handelt (also
dass dem Compiler lediglich gesagt werden soll, dass irgendwo eine
Variable mit den spezifizierten Eigenschaften existiert).
Bei Funktionen ist das extern überflüssig, da aus der Syntax
ersichtlich ist, ob es sich um eine Definition oder eine Deklaration
(Prototyp) handelt.
Ja das meine ich ja auch.
Also nochmal:
init.h
------
int g[2]={0,1}; //Variable - das sollte gehen oder ?
void g_f(void); //Prototyp
init.c
------
#include "init.h"
void g_f(void) //Funktionsdefinition
{
a=g[1];
b=g[2];
}
main.c
------
#include "init.h"
main()
{
g_f(); //Aufruf
}
int g[2]={0,1}; //Variable - das sollte gehen oder ?
ist eine Definition
Die Deklaration sähe so aus
extern int g[]; //Variable - das sollte gehen oder ?
Wenn du die Definition in die init.h steckst (wie derzeit) und die
init.h in int.c und main.c einbindest, dann legst du das Feld g doppelt
an.
du willst aber das Feld g nur einmal anlegen z.B. in init.c, also ist
dort die Definition einzufügen. Und in main.c willst du den Namen und
den Typ bekanntmachen, also ist dort die Deklaration einzufügen z.B.
über init.h
Es stört in init.c nicht, wenn dort die Definition und die Deklaration
sichtbar sind, d.h. über das #include von init.h das extern...
auftaucht.
Herbert wrote:
> Ja das meine ich ja auch.>> Also nochmal:>> init.h> ------>> int g[2]={0,1}; //Variable - das sollte gehen oder ?
Nö, eben nicht. Da muss ein extern davor und der Initialisierungswert
weg. Und dann mit Initialisierung ohne extern (also die Definition )
in die entsprechende .c-Datei.
Hallo,
danke für eure Antworten.
Wie mache ich es, dass man in init.c eine Variable definiert und in main
verändert ?
Brauche ich dafür nur die init.h einbinden ?
Also:
init.h
------
extern int g[];
init.c
------
#include "init.h"
int g[2]={0,1}
main.c
------
#include "init.h"
main()
{
g[2]=0;
}
Jo, genau so ist es. Ich vermute, dass Dir der Unterschied zwischen
"Definition" und "Deklaration" noch nicht ganz klar ist.
Definition : Eine Variable wird angelegt, d.h. es wird angemessener
Speicherplatz für sie reserviert. Das muss für jede Variable / Funktion
genau einmal gemacht werden.
Deklaration : Es wird dem Compiler mitgeteilt, dass es irgendwo
außerhalb seines momentanen Blickfeldes eine Definition der betreffenden
Variable gibt. Es ist aber nur eine formelle Mitteilung an den Compiler
"tu so, als wäre die Variable da und arbeite mit ihr". Das kann man
beliebig oft machen.
Der Compiler bearbeitet jede Quelldatei (.c-Datei) völlig separat, also
unabhängig von anderen Quelldateien. Das bedeutet aber auch, dass er
Variablen und Funktionen, in anderen Source-Files definiert wurden,
nicht sehen kann. Er darf die Variable dann aber nicht neu anlegen, denn
es soll ja die Variable aus der anderen Datei verwendet werden. Deshalb
braucht er dann einfach nur einen Hinweis, dass die Variable existiert
(wenn sie das natürlich nicht tut, dann meckert der Linker eben aus dem
Grunde...).
Erst der Linker fügt die einzelnen Objekt-Files, die der Compiler
erzeugt, zu einer Gesamtheit zusammen. Und deshalb ist er es auch, der
(berechtigt) meckert, wenn für eine Variable mehrfach Speicherplatz
angefordert wurde.
Allerdings solltest Du beim Arrayzugriff auch die zulässigen Grenzen
berücksichtigen.
Wird das Array so definiert:
int g[2]={0,1}
dann geht folgender Schreibzugriff in die Hose:
g[2]=0;
Das Array hat nur zwei und nicht drei Elemente, und in C ist das erste
Element [0] und nicht [1].
Johannes M. wrote:
> Jo, genau so ist es. Ich vermute, dass Dir der Unterschied zwischen> "Definition" und "Deklaration" noch nicht ganz klar ist.
Ich habe auf der FAQ Seite da mal einen Abschnitt dazu
eingebaut, damit man sich über solche Sachen nicht mehr den
Mund fusselig redet :-)
http://www.mikrocontroller.net/articles/FAQ#Globale_Variablen_.C3.BCber_mehrere_Dateien
Karl heinz Buchegger wrote:
> Ich habe auf der FAQ Seite da mal einen Abschnitt dazu> eingebaut, damit man sich über solche Sachen nicht mehr den> Mund fusselig redet :-)
Danke!
Mir ging es auch gerade durch den Kopf, dass dieses Thema in letzter
Zeit verdammt häufig aufgetaucht ist.
Hallo,
ich denke, dass es mir schon klar ist.
Wenn ich eine Variable in init.c DEFINIERE, dann muss ich in main()
diese bekanntmachen, also mit EXTERN. Dann kann ich Sie in ganz normal
benutzen.
Sie wird nicht nochmal angelegt.
Zu meinem Beispiel:
init.h
------
EXTERN int g[];
init.c
------
#include "init.h" //Optional
int g[2]={0,1}
main.c
------
#include "init.h"
EXTERN int g[]; //Keine neue Definition, sondern DEKLARATION
main()
{
g[1]=0;
}
Ist das jetzt korrekt ?
erstens: Antwort auf deinen vorletzen Post:
> Jo, genau so ist es.
Warum änderst du es jetzt noch wieder?
zweitens: Überleg mal, was der preprozessor mit dem #include aus deiner
main.c macht:
main.c
------
EXTERN int g[];
EXTERN int g[]; //Keine neue Definition, sondern DEKLARATION
main()
{
g[1]=0;
}
Herbert wrote:
> Ist das jetzt korrekt ?
Nein.
In der Programmiersprache C ist korrekte Groß-/Kleinschreibung
wichtig.
Das Schlüsselwort heißt 'extern', nicht 'EXTERN'
Abgesehen davon ist es ok, auch wenn es die 2.-te Deklaration
in main.c nicht gebraucht hätte. Durch das #include hast du
ja sowieso eine Deklaration verfügbar.
Also ich habe soeben ebenfalls ein Problem aus diesem Bereich erlebt:
Und zwar habe ich eine Header Datei Namens eeprom.h mit folgendem Inhalt
erzeugt:
>eeprom.h:>#include <avr/io.h>>#include <avr/eeprom.h>>uint8_t EE_SPEICHER EEMEM;
Sobald ich diese in zwei anderen c-Files eingebunden habe, hat der
Compiler gemeckert... und das hat mich verwundert, weil ich ja nach der
Section-Bekanntgabe garkeinen Wert an die EEPROM-Speicherstelle
überschrieben habe...
Nun habe ich eeprom.c noch dazu angelegt und folgende Änderungen
vorgenommen:
>>eeprom.h:>>#include <avr/io.h>>>#include <avr/eeprom.h>>>>>uint8_t EE_SPEICHER; //Deklaration>>>eeprom.c:>>>#include "eeprom.h">>>>>>uint8_t EE_SPEICHER EEMEM; //Definition
Dieses "Konstrukt" kann ich problemlos in mehreren artfremden C-Files
mit einbinden..., aber eine Frage habe ich nun dazu:
Frage:
Wird die Variable EE_SPEICHER bei Verwendung der Funktionen
>X = eeprom_read_byte(&EE_SPEICHER);
bzw.
>eeprom_write_byte(&EE_SPEICHER, 123);
nun auch tatsächlich als einmalig und global angesehen, oder habe ich
hier immernoch etwas nicht richtig verstanden?
mfg
EEPROM schrieb:> Nun habe ich eeprom.c noch dazu angelegt und folgende Änderungen> vorgenommen:>>>>eeprom.h:>>>#include <avr/io.h>>>>#include <avr/eeprom.h>>>>>>>uint8_t EE_SPEICHER; //Deklaration
Das ist nach wie vor eine Defintion und keine Deklaration.
Hallo Karl Heinz,
...das EEMEM ist demnach garkeine Definition und die Code-Zeile:
>> extern uint8_t EE_SPEICHER EEMEM;
genügt als Header in allen C-Files zu inkludieren?
mfg
...und vor allem,
was schreieb ich denn als Definition in die eeprom.c, wenn die Codezeile
>> extern uint8_t EE_SPEICHER EEMEM;
eine Deklaration darstellen sollte...
EEPROM schrieb:> was schreieb ich denn als Definition in die eeprom.c, wenn die Codezeile>>>> extern uint8_t EE_SPEICHER EEMEM;>> eine Deklaration darstellen sollte...
Wie wäre es mit einer Definition?
uint8_t EE_SPEICHER EEMEM;