Forum: Compiler & IDEs Globale Variable - undefined reference


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von W3ll S. (w3llschmidt)


Bewertung
0 lesenswert
nicht lesenswert
Hallo Leute,

ich sitze hier schon eine Weile dran:
//main.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <sub.h>

void app_main() {

  strcpy(string_array, "Hallo");

  printf("%d\n", zahl );
  printf("%s\n", string_array );

}
//sub.h

#ifndef SUB_H
#define SUB_H

  extern int zahl;
  extern char string_array[];

#endif
//sub.c

#include <sub.h>

void a_task() {

  int zahl = 5;
  char string_array[100];

}

Ich bekomme es nicht hin. Wenn ich zahl und string_array aus der 
Funktion
eine Ebene nach oben lege (wo sie dann wohl automatisch extern werden) 
funktioniert es.

Lass ich die Variablen im Funktionsblock bekomme ich: undefined 
reference to ''

von Zombie (Gast)


Bewertung
2 lesenswert
nicht lesenswert
W3ll S. schrieb:
> Lass ich die Variablen im Funktionsblock bekomme ich: undefined
> reference to ''

Logisch, sind ja dann auch lokale Variablen, auf die kannst Du nur 
innerhalb der Funktion zugreifen. Entweder lokal oder global, beides 
geht nicht.

von Peter S. (psavr)


Bewertung
0 lesenswert
nicht lesenswert
>..eine Ebene nach oben lege (wo sie dann wohl automatisch extern werden)
>funktioniert es.

So werden sie global, nicht extern. Variabeln die du innerhalb einer 
Funktion deklarierst sind immer lokal.

von Dirk B. (dirkb2)


Bewertung
0 lesenswert
nicht lesenswert
W3ll S. schrieb:
> wo sie dann wohl automatisch extern werden

Nein.
Das extern kennzeichnet die Deklaration.
Ohne extern ist es eine Definition.

Zombie schrieb:
> Entweder lokal oder global,

Es geht noch static.

von ccc (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Vertausch diese beiden Zeilen:
void a_task() {

  int zahl = 5;

von W3ll S. (w3llschmidt)


Bewertung
0 lesenswert
nicht lesenswert
Ahh, ok danke!

Ich dachte echt, in kann Variablen in einem Headerfile 'extern' 
deklarieren, dann in einer Funtion definieren und überall wo ich das 
Headerfile einbinde, drauf zugreifen ...

von Rolf M. (rmagnus)


Bewertung
0 lesenswert
nicht lesenswert
Peter S. schrieb:
>>..eine Ebene nach oben lege (wo sie dann wohl automatisch extern werden)
>>funktioniert es.
>
> So werden sie global, nicht extern.

Doch, extern werden sie dadurch auch.

Dirk B. schrieb:
> Das extern kennzeichnet die Deklaration.

Ja, im Quellcode macht ein vorgestelltes "extern" eine Deklaration 
draus.

> Ohne extern ist es eine Definition.

Dennoch hat die Variable "external linkage". Man kann also von anderen 
Übersetzungseinheiten aus darauf zugreifen. Wenn man das vermeiden 
wollte, müsste sie static gemacht werden.

von Dirk B. (dirkb2)


Bewertung
0 lesenswert
nicht lesenswert
W3ll S. schrieb:
> dann in einer Funtion definieren und überall wo ich das
> Headerfile einbinde, drauf zugreifen

Woher soll der Compiler/Linker denn wissen, welche Funktion gemeint ist?

von W3ll S. (w3llschmidt)


Bewertung
0 lesenswert
nicht lesenswert
Danke!

von Mike (Gast)


Bewertung
-1 lesenswert
nicht lesenswert
>Ich dachte echt, in kann Variablen in einem Headerfile 'extern'
>deklarieren, dann in einer Funtion definieren und überall wo ich das
>Headerfile einbinde, drauf zugreifen ...

Mit 'extern' wird keine Variable deklariert.
=> Damit sagst Du dem Compiler, dass die Variable in einem anderen Modul 
(Global) deklariert wird. Der Compiler soll einfach die angegeben 
Definition verwenden, der Linker kümmert sich dann um die Refernz, bzw. 
meckert wenn er keine Refernz dazu findet.

Der Linker findet die Referenz nicht wenn:
- Die Variable Lokal (=innerhalb einer Funtion) deklariert ist
- Die Variable als 'static' definiert ist (=> Keine Linker Refernz)

von Mike (Gast)


Bewertung
-2 lesenswert
nicht lesenswert
..aber statt 'extern' zu nutzen ist es eleganter, globale 
Variabeln-Definitionen via Headerfiles zu includieren.

von Dirk B. (dirkb2)


Bewertung
2 lesenswert
nicht lesenswert
Mike schrieb:
> Mit 'extern' wird keine Variable deklariert.
> => Damit sagst Du dem Compiler, dass die Variable in einem anderen Modul
> (Global) deklariert wird.

Ja was denn nun? Deklariert oder nicht?

Mike schrieb:
> ..aber statt 'extern' zu nutzen ist es eleganter, globale
> Variabeln-Definitionen via Headerfiles zu includieren.

Niemals.


Variablen werden in .c Dateien definiert
Und in Headerdateien - wenn nötig - deklariert.

Die Unterscheidung zwischen Definition und Deklaration macht das extern.

: Bearbeitet durch User
von Uwe W. (Firma: LCD-Solution SAS) (upwettin)


Bewertung
0 lesenswert
nicht lesenswert
Gibt es Literatur über das Thema, die in kurzen Worten alle Fälle (von 
lokalen, globalen und statischen Variablen) abdeckt und in den 
Kommentaren etwas beschreibt?
Quasi 4 Dateien (main.c, main.h, thema.c und thema.h)

Noch eine Frage zum Beispiel ganz oben. Muss in main.c nicht a_task() 
aufgerufen werden?

Gruß UPW

von W3ll S. (w3llschmidt)


Bewertung
0 lesenswert
nicht lesenswert
Mike schrieb:
> ..aber statt 'extern' zu nutzen ist es eleganter, globale
> Variabeln-Definitionen via Headerfiles zu includieren.

Hallo Mike,

machte mal ein Beispiel bitte?

von zitter_ned_aso (Gast)


Bewertung
0 lesenswert
nicht lesenswert
das geht docht nicht. Man kann nicht die gleiche Variable mehrmals 
defininieren.

von Dirk B. (dirkb2)


Bewertung
1 lesenswert
nicht lesenswert
Jede .c-Datei wird für sich alleine compiliert.
Vorweg läuft noch der Preprozessor. Der ersetzt z.B. die Zeile #include 
"meins.h" durch den Inhalt der Datei meins.h

Der eigentliche Compiler sieht von den Preprozessoranweisungen nichts.
Er weiß nichts von anderen Dateien.
Er übersetzt die .c Dateien in Object-Dateien. Diese werden dann (mit 
den Bibliotheken) vom Linker zu einer ausführbaren Datei zusammen 
gebunden.

Wenn jetzt in einer Headerdatei Variablen definiert werden und dieser 
Header in mehreren .c-Dateien inkludiert werden, dann werden diese 
Variablen mehrmals angelegt.
Das gefällt dem Linker nicht so gut.

Werden die Variablen aber in der .c definiert und in den Headern 
deklariert, gibt es diese Variable nur einmal.

Globale Variablen sollte man so wenig wie möglich nutzen.

Ein globales i (selber gesehen) kann sehr irritierend sein.

von DPA (Gast)


Bewertung
0 lesenswert
nicht lesenswert
W3ll S. schrieb:
> Mike schrieb:
>> ..aber statt 'extern' zu nutzen ist es eleganter, globale
>> Variabeln-Definitionen via Headerfiles zu includieren.
>
> Hallo Mike,
>
> machte mal ein Beispiel bitte?

Man könnte das so machen (ungetestet):

Makefile
HEADERS = a.h b.h
OBJECTS = vars.gen.o bla.o blup.o
DEPS = $(HEADERS)

all: myfancyprogram

# Include everything in one file to make sure all headers are only pulled in once
vars.gen.c: $(HEADERS)
  ( \
    echo '#define GENCODE'; \
    echo '#include "vars-gen.h"'; \
    for header in $^; \
      do echo "#include \"$$header\""; \
    done; \
  ) > $@

%.o: %.c $(DEPS)
  $(CC) -c -o $@ $< $(CFLAGS)

myfancyprogram: $(OBJECTS)
  $(CC) -o $@ $^

vars-gen.h
#ifndef VARS_GEN_H
#define VARS_GEN_H

#ifdef GENCODE
#define EXTDEF
#else
#define EXTDEF extern
#endif

#endif

a.h:
#ifndef A_H
#define A_H

#include "vars-gen.h"

EXTDEF int a;

#endif

b.h:
#ifndef B_H
#define B_H

#include "vars-gen.h"

EXTDEF int b;

#endif

bla.c:
#include "a.h"
#include "b.h"
...

blup.c:
#include "a.h"
#include "b.h"
...

Würde ich aber nicht empfehlen.

von DPA (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Alternativ könnte man alle Symbole weak machen.

von Andreas S. (Firma: Schweigstill IT) (schweigstill) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert
Einen ganz fieser Fallstrick gibt es bei globalen Variablen, wenn man 
sein Projekt nicht nur auf Quellcodeebene schön strukturiert, sondern 
die einzelnen Kompilate zunächst zu Bibliotheken linkt und anschließend 
diese Bibliotheken, ggf. mit einzelnen Objektdateien, zur eigentlichen 
Applikation. Je nach Linkereinstellungen sind globale Variable dann 
nicht außerhalb einer Bibliothek sichtbar, und wenn von einem anderen 
Programmteil auf solch eine globale Variable zugegriffen werden soll, 
wird nämlich daneben gegriffen. Solch ein Problem hatte ich mal vor 
ewiger Zeit(tm) bei einer Applikation, die ich von Ultrix auf Windows NT 
portieren musste. Wenn ich mich recht einnere, fasste der C-Compiler 
unter Ultrix beim Linken gleichnamige globale Variable, die in mehrere 
Bibliotheken definiert wurden, zu einer gemeinsamen zusammen. Microsoft 
C hingegen legte dann pro Bibliothek eine Instanz an, was meines 
Erachtens in den meisten Fällen auch sinnvoll ist, denn gerade bei 
fremden Bibliotheken könnte es ja sonst auch zu unbeabsichtigten 
Übereinstimmungen kommen.

Wenn man Bibbliotheken zur Verwendung durch Dritte erstellt, sollte man 
am Besten auch in einer entsprechenden Linkersteuerdatei explizit die 
Symbole benennen, die nach außen sichtbar sein sollen, und alle anderen 
Symbole verbergen.

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.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.