Forum: PC-Programmierung lokale vs globale variable


von Hans F. (dani1632)


Lesenswert?

Hallo!

Ich habe bereits intensiv danach gegoogelt, hätte aber noch eine Frage 
zu globalen und lokalen Variablen bei der C-Programmierung:

Folgende Dateien werden verwendet: main.c, testfunktion.c, 
testfunktion.h

main.c:
1
#include "testfunktion.h"
2
3
int global_variable = 0;
4
5
int main()
6
{
7
   int lokal_variable = 0;
8
   testfunktion();
9
   return(0);
10
}

testfunktion.h:
1
void testfunktion(void);

testfunktion.c:
1
int testvariable = 0;
2
3
void testfunktion()
4
{
5
   ... führt bestimmte funktion aus...
6
}

Meine Frage dazu betrifft die Variable "testvariable": Ist diese nun 
global oder lokal? Ich habe das so verstanden, dass diese Variable 
global ist, weil sie außerhalb eines Funktionsblockes definiert ist. Ist 
das korrekt? Wenn ich nun auf diese globale Variable in einem anderen 
c-file zugreifen will (z.B. in der main), dann muss ich in 
testfunktion.h diese testvariable als extern deklarieren und mit 
#inklude "testfunktion.h" in diesem c-file einfügen? Habe ich das 
richtig verstanden?

Vielen Dank für eure Hilfe!

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Daniel F. schrieb:
> Ich habe das so verstanden, dass diese Variable global ist, weil sie
> außerhalb eines Funktionsblockes definiert ist. Ist das korrekt?

Ja.

Du könntest allerdings diese Variable auch als static definieren, dann 
ist sie nur innerhalb des C-Files nutzbar, in dem sie definiert ist. Aus 
anderen C-Files heraus ist sie auch mit /extern/-Deklaration dann nicht 
ansprechbar.

> Wenn
> ich nun auf diese globale Variable in einem anderen c-file zugreifen
> will (z.B. in der main), dann muss ich in testfunktion.h diese
> testvariable als extern deklarieren und mit #inklude "testfunktion.h" in
> diesem c-file einfügen?

Ja, so wird es "ordentlich" gemacht. Du könntest zwar auch die 
extern-Deklaration direkt in das andere C-File einfügen, aber das ist 
aus mehreren Gründen kein sauberer Stil.

> Habe ich das richtig verstanden?

Richtig!

von Stefan (Gast)


Lesenswert?

bis auf #inklude ;) , ja!
Stefan

von Hans F. (dani1632)


Lesenswert?

Sollte natürlich #include heißen :)
Vielen Dank für Eure rasche Hilfe, dann hab ich das richtig verstanden!
LG

von Hans F. (dani1632)


Lesenswert?

Kurze Frage noch dazu:
Angenommen, ich würde das Programm nicht auf mehrere Files aufteilen, 
sondern alles in einem c-file schreiben. Dann bräuchte ich keine 
Deklaration, die Definition einer globalen Variable würde ausreichen, 
richtig? Dann kann ich innerhalb des gesamten Files (innerhalb und 
außerhalb von Funktionsblöcken) auf diese Variable zugreifen.

Wenn ich aber mehrere Files verwende, dann muss ich bei jenen Files, in 
denen die globale Variable nicht definiert wurde, die Deklaration 
einfügen??

Vielen Dank, LG

von Andreas B. (andreas_b77)


Lesenswert?

Daniel F. schrieb:
> Wenn ich aber mehrere Files verwende, dann muss ich bei jenen Files, in
> denen die globale Variable nicht definiert wurde, die Deklaration
> einfügen??

Ja, eine Deklaration mit "extern". Allerdings solltest du die nicht 
direkt manuell einfügen sondern per #include einer Header-Datei. Und 
dann diese Header-Datei mit der Deklaration auch in die Datei #includen, 
wo die Variable tatsächlich definiert wird.

So ist dann sichergestellt, dass alle extern-Deklarationen und die 
Definition zueinander passen, denn der Compiler kann dann bei 
Abweichungen eine Warnung oder Fehler ausgeben.

von Hans F. (dani1632)


Lesenswert?

Alles klar, vielen Dank!

von Tom K. (ez81)


Lesenswert?

Auch wenn das nicht gefragt war:
Du solltest Dir überlegen, auf globale Variablen soweit wie möglich zu 
verzichten. Funktionen, denen man Ein- und Ausgabedaten nicht an der 
Deklaration ansieht, sondern die heimlich in irgendwelchen Daten 
herumpfuschen, sind eine Pest und machen Debuggen und Testen 900x 
schwieriger. Selten geht es nicht anders (ISR im Microcontroller), aber 
meistens sind globale Variablen ein Zeichen von verbesserungswürdiger 
Programmstruktur. Ich kann mich nicht erinnern, wann ich zuletzt 
'extern' benutzt habe.

main.c:
1
#include "testfunktion.h"
2
3
int main()
4
{
5
   int lokal_variable = 0;
6
   int nichtmehrglobal = 0;
7
   testfunktion(&nichtmehrglobal); 
8
   // aha, hier wird nur 'nichtmehrglobal' veraendert!
9
   // wie praktisch, dass das an dieser Stelle erkennbar ist,
10
   // ohne in testfunktion.c nachzusehen.
11
   return(0);
12
}

testfunktion.h:
1
/** setzt foo auf 42 */
2
void testfunktion(int* foo);

testfunktion.c:
1
void testfunktion(int* foo)
2
{
3
   *foo = 42;
4
}

von Rosa-Kleidchen (Gast)


Lesenswert?

>Du solltest Dir überlegen, auf globale Variablen soweit wie möglich zu
>verzichten.
Hmm! In Zeiten, wo Speicher knapp war, waren globale Variablen das A und 
O. Der kleine Stack konnte es nicht ab, mit lokalen Variablen 
überschwemmt zu werden. Bei FPGAs mit wenig BRAM oder wenig externes RAM 
bin ich mit globalen Variablen immer gut gefahren. Ein anderes Thema 
sind Rekursionen...
Rosa

von (prx) A. K. (prx)


Lesenswert?

Rosa-Kleidchen schrieb:
> Hmm! In Zeiten, wo Speicher knapp war, waren globale Variablen das A und
> O. Der kleine Stack konnte es nicht ab, mit lokalen Variablen
> überschwemmt zu werden.

Das kann man auch genau umgekehrt sehen. ;-)

Wenn man alle Variablen global anlegt, dann ist der Platzverbrauch eher 
grösser, als wenn man lokale Variablen verwendet und auf den Stack legt. 
Denn mit einem Daten-Stack verwenden lokalen Variablen vieler Funktionen 
dengleichen RAM-Bereich, während die bei globalen Variablen nicht der 
Fall ist.

von Karl H. (kbuchegg)


Lesenswert?

Wir sind hier im Unterforum "PC-Programmierung".
Hier gelten die Sonderregeln der µC-Programmierung nur eingeschränkt 
bzw. gar nicht, sondern die des guten Software-Designes.
Von daher: Modulkapselung und weitgehender Verzicht auf globale 
Variablen.
Wobei 'Verzicht' das falsche Wort ist. Denn eigentlich will man die nach 
Möglichkeit überhaupt nicht haben und nimmt sie zähneknirschend auf den 
kleinen µC in Kauf um den Tools eine Möglichkeit zu geben, den 
Gesamtspeicherverbrauch einigermassen realistisch bestimmen zu können.

von Rene M. (Firma: RWTH Aachen) (rene_m)


Lesenswert?

Tom K. schrieb:
> Auch wenn das nicht gefragt war:
> Du solltest Dir überlegen, auf globale Variablen soweit wie möglich zu
> verzichten. Funktionen, denen man Ein- und Ausgabedaten nicht an der
> Deklaration ansieht, sondern die heimlich in irgendwelchen Daten
> herumpfuschen, sind eine Pest und machen Debuggen und Testen 900x
> schwieriger. Selten geht es nicht anders (ISR im Microcontroller), aber
> meistens sind globale Variablen ein Zeichen von verbesserungswürdiger
> Programmstruktur. Ich kann mich nicht erinnern, wann ich zuletzt
> 'extern' benutzt habe.

Rosa-Kleidchen schrieb:
> Hmm! In Zeiten, wo Speicher knapp war, waren globale Variablen das A und
> O. Der kleine Stack konnte es nicht ab, mit lokalen Variablen
> überschwemmt zu werden.


Schöne Statments, aber wie sieht das hinsichtlich der Geschwindigkeit 
eines Programms aus?
Wenn ich durch jeden Zyklus(Hauptschleifengang) diverse lokale Variablen 
definiere indem ich Unterprogramme/Prozeduren aufrufe verbraucht das 
doch einige Takte, wobei globale Variablen nur einmal zu Beginn 
deklariert werden.

Daher würde ich auf lokale Variablen verzichten wenn ich z.B. permanent 
16 ADC Eingänge über ein Mikrocontroller einlese und über USB Verbindung 
weiter verarbeiten möchte?

: Bearbeitet durch User
von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Rene Müller schrieb:
> Wenn ich durch jeden Zyklus(Hauptschleifengang) diverse lokale Variablen
> definiere indem ich Unterprogramme/Prozeduren aufrufe verbraucht das
> doch einige Takte

Wieso sollte es das tun?
Dazu wird bei Funktionseintritt der Stackpointer entsprechend 
erhöht/erniedrigt, und ob das um x oder um y Bytes geschieht, dürfte 
keinerlei Laufzeitunterschied haben.

Bedenke: Lokale Variablen werden nicht initalisiert, es sei denn, Du 
tust das explizit, dann braucht das natürlich Zeit. Aber dann ist der 
Vergleich mit einer globalen Variablen nicht mehr gerechtfertigt.

von Rene M. (Firma: RWTH Aachen) (rene_m)


Lesenswert?

Rufus Τ. Firefly schrieb:
> Bedenke: Lokale Variablen werden nicht initalisiert, es sei denn, Du
> tust das explizit, dann braucht das natürlich Zeit. Aber dann ist der
> Vergleich mit einer globalen Variablen nicht mehr gerechtfertigt.

Da war was.
Was genau verstehst du unter explizit?
Mit malloc ?

Also wenn ich es so definiere
1
static uchar scankeys(void)
2
{   
3
    uchar reportIndex=2; /* First available report entry is 2 */
4
    uint8_t i;
5
  uint8_t retval=0;
6
    uint8_t keys[2];   
7
    static uint8_t keybuf[2];   
8
    static uint8_t trigbuf = 0;
9
  static uint8_t debounce = 5; //entprellen
10
...

ist es deutlich besser als wenn ich es global definiere?

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Rene Müller schrieb:
> Da war was.
> Was genau verstehst du unter explizit?
> Mit malloc ?

Initialisieren. Keine dynamische Speicherverwaltung.

> Also wenn ich es so definiere
> ...
> ist es deutlich besser als wenn ich es global definiere?

"Besser" ist immer eine Frage des Standpunkts. Es ist jedenfalls nicht 
langsamer, als wenn Du globale Variablen verwenden würdest.

Wobei zwei Deiner Variablen initialisiert werden, d.h. bei jedem 
Aufruf Deiner Funktion auf einen definierten Wert gesetzt werden. Das 
sind reportIndex und retval. Da die bei jedem Funktionsaufruf erneut 
initialisiert werden, braucht diese Initialisierung natürlich 
Rechenzeit, die nicht verbraucht würde, wenn Du globale Variablen 
verwenden würdest --- allerdings würdest Du die ja auch nicht bei jedem 
Funktionsaufruf erneut auf einen festen Wert setzen, und daher ist der 
Vergleich nicht wirklich zulässig.

Ob es nötig ist, diese Variablen jedesmal neu zu initialisieren, das 
lässt sich ohne Betrachtung des Codes nicht erkennen.

Die anderen Variablen, die initialisiert werden, sind statische 
Variablen, bei denen das genau einmal passiert, und die liegen auch 
nicht auf dem Stack.

von (prx) A. K. (prx)


Lesenswert?

Rene Müller schrieb:
> Daher würde ich auf lokale Variablen verzichten

Das wird ein krachender Schuss in den Ofen.

Wenn es sich um Skalare handelt und der Prozessor einige Register hat, 
wie AVR, ARM, x86-64 und sogar x86-32, wird der Compiler sie soweit 
möglich in Registern halten. Bei globalen Variablen ist das wesentlich 
schwieriger.

Bei 32- und 64-Bit RISC-Prozessoren wie ARM und MIPS(PIC32) ist zudem 
der Zugriff auf statisch adressierte globale Variablen wesentlich 
aufwändiger als auf lokale Variablen auf dem Stack. Aber auch bei x86 
ist der Unterschied mindestens in der Codegrösse markant.

Da wie hier im PC-Forum sind kommen auch noch Caches hinzu. Und da 
stehen die Chancen beim Stack sehr viel besser als bei statischen Daten.

: Bearbeitet durch User
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.