Forum: Compiler & IDEs Problem mit globaler Variable


von Günther F. (taraquedo)


Lesenswert?

Hallo!

Ich habe gerade versucht meine globalen Variablen in eine cmd.h 
auszulagern. Es geht z.B. um eine Variable vom Typ uint8_t mit der 
Bezeichnung who. Diese wird außerdem in cmd.c von einer Funktion, sagen 
wir be_my_admin(), verändert.

Jetzt habe ich eben schmerzlich erfahren, dass wenn man static in cmd.h 
benutzt die Variable wohl irgendwie zweimal existiert und jede Änderung 
nicht in main.c ankommt. Also habe ich static weggelassen und jetzt 
dreht mir der Compiler durch! Er sagt mir ich hätte who mehrmals 
definiert. Laut Suchfunktion habe ich aber in allen Datei nur ein 
einziges Mal who in Verbindung mit uint8_t geschrieben. Außerdem kommt 
diese Fehlermeldung nicht wie üblich unter "Build" mit rotem Punkt zum 
Vorschein, sondern erst "Message", dass es PRobleme mit der elf-Datei 
gibt.

cmd.o:(.data+0x4): multiple definition of `who'
main.o:(.data+0x0): first defined here

Irgendwas trotteliges steckt im Code drin, denn ich habe versucht den 
Fehler "im kleinen" zu reproduzieren und da lief es. Also so habe ich es 
versucht nachzustellen, aber wie gesagt - das funktioniert so:
1
// --- main.c ----------------------------
2
#include "cmd.h"
3
extern uint8_t who; // mit oder ohne diese Zeile spielt keine Rolle
4
5
int main(void)
6
{
7
   who = 0;
8
   be_my_admin();
9
   return 0;
10
}
11
// --- cmd.h -----------------------------
12
#ifndef CMD_H
13
#define CMD_H
14
15
#include <stdint.h>
16
17
#define UID_ADMIN 0xFF
18
19
uint8_t who;
20
21
void be_my_admin(void);
22
23
#endif
24
// --- cmd.c -----------------------------
25
#include "cmd.h"
26
27
void be_my_admin(void)
28
{
29
   who = UID_ADMIN;
30
   return;
31
}

Fällt irgendjemanden spontan ein, wo ich suchen muss? Dieser Fehler 
nervt mich ganz besonders, weil vor dem Umpacken alles so schön 
funktionierte.

Grüße!

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Du vertauscht Definition und Deklaration.

In die Headerdatei gehört

  extern uint8_t who;

In genau EIN Sourcefile gehört

  uint8_t who.

von Günther F. (taraquedo)


Lesenswert?

Ahhh vielen Dank! Da habe ich genau falsch herum gedacht. Dann ist das 
mit dem extern also auch wieder so eine Sache dem Compiler so lange 
ruhig zu stellen und zu sagen "die Variable gibt es irgendwo, die 
Adresse wird dir der Linker sagen". Das macht natürlich alles viel mehr 
Sinn.

Interessanterweise hatte ich jetzt noch gerade herausgefunden, dass 
dieses o.g. Problem nur dann auftritt, wenn ich in cmd.h die Variable 
initialisiere. Sagen wir uint8_t who = UID_NOBODY; schreibe. Ohne, so 
wie oben, funktionierte es. Klar, weil ich im "Miniprogramm" den Header 
nur einmal in main.c eingebunden habe. Aber auch im Miniprogramm läuft 
es dann nicht mehr mit Initialisierung. Das wäre spannend zu wissen, was 
hier der Compiler für einen Unterschied macht.

Aber das Problem konnte ich lösen, vielen Dank!

von Karl H. (kbuchegg)


Lesenswert?

Günther Frings wrote:
> Interessanterweise hatte ich jetzt noch gerade herausgefunden, dass
> dieses o.g. Problem nur dann auftritt, wenn ich in cmd.h die Variable
> initialisiere. Sagen wir uint8_t who = UID_NOBODY; schreibe. Ohne, so
> wie oben, funktionierte es.

Das Problem ist, dass in C eine Initialisierung immer mit
einer Definition verbunden ist. In dem Moment, wo eine
Initialisierung vorhanden ist, wird das als Definition aufgefasst,
unabhängig davon, ob ein extern davor steht.

von Nico G. (ockerle)


Lesenswert?

Hi,

ich bin noch anfänger deswegen ist die frage vlt. ein bisschen blöd, 
aber ich habe etwas nicht ganz verstanden.
Ich habe in meiner Header Datei folgendes stehen:

   extern int globalevariable;

dann in einem anderen c file die definition

   int globale variable;

aber ich muss doch auch irgendwo einen Wert zuweisen odernicht? wenn ich 
also in einem 3. c file einen Wert zuweien will kommt die Fehlermeldung 
diese Deklaration hat keine Speicherklasse... was habe ich also falsch 
verstanden?
Ich habe die Header Datei ja immer inkludiert....

von Yalu X. (yalu) (Moderator)


Lesenswert?

Du musst unterscheiden zwischen einer Zuweisung und einer
Initialisierung. Eine Zuweisung kann beliebig oft erfolgen, aber nur
innerhalb von ausführbarem Code, d.h. nur innerhalb von Funktionen.

Eine Initialisierung erfolgt nur ein einziges Mal direkt beim
Programmstart und ist Bestandteil der Variablendefinition, also bspw.

1
int globalevariable = 42;

Du hast vermutlich

1
globalevariable = 42;

irgendwo außerhalb einer Funktion hingeschrieben. Das ist weder eine
Initialisierung noch eine Zuweisung und deswegen ein Fehler.

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.