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
intglobal_variable=0;
4
5
intmain()
6
{
7
intlokal_variable=0;
8
testfunktion();
9
return(0);
10
}
testfunktion.h:
1
voidtestfunktion(void);
testfunktion.c:
1
inttestvariable=0;
2
3
voidtestfunktion()
4
{
5
...führtbestimmtefunktionaus...
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!
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!
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
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.
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
intmain()
4
{
5
intlokal_variable=0;
6
intnichtmehrglobal=0;
7
testfunktion(&nichtmehrglobal);
8
// aha, hier wird nur 'nichtmehrglobal' veraendert!
9
// wie praktisch, dass das an dieser Stelle erkennbar ist,
>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
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.
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.
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?
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.
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
staticucharscankeys(void)
2
{
3
ucharreportIndex=2;/* First available report entry is 2 */
4
uint8_ti;
5
uint8_tretval=0;
6
uint8_tkeys[2];
7
staticuint8_tkeybuf[2];
8
staticuint8_ttrigbuf=0;
9
staticuint8_tdebounce=5;//entprellen
10
...
ist es deutlich besser als wenn ich es global definiere?
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.
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.