Anfängerhilfe bei static Variablen

Gast #785256
Lesenswert?

Hallo,

ich bin blutiger Anfänger in C und schreibe derweil an einem Programm 
für eine Nixie Uhr als "Aufbaukurs".

In meiner ersten Version des Programmes war alles in ein main-File 
gestopft.
Das wollte ich nun abändern und habe mich an ein neues Programm gesetzt, 
wo ich jede Funktion in sein eigenes .c File schreibe, damit ich später 
auch mal etwas umfangreiche Programme schreiben kann.

Da es sich ja um eine Uhr handelt habe ich 3 Variablen stunden, minuten 
und sekunden. Diese habe ich dann als static gesetzt (global geht ja nur 
in einem .c File ?), da ich mehrere "ausgelagerte" Funktionen in .c 
Files habe die die Uhrzeit-Variablen verändern bzw. benutzen ( 
Uhrzeitstellen, eine Interruptroutine und die Ausgabefunktion ). Da ich 
die Variablen in Headerfiles drin hab, meckert das AVR-Studio nun 
andauernd über deklarierte aber nicht benutzte Variablen in main.

Jetzt meine Frage : Gibt es noch eine andere möglichkeit die 3 
Uhrzeit-Variaben aus den einzelnen Funktionen heraus zu ändern, ohne das 
ich die statischen Variablen benutzen muß ? Wenn ja, wie kann ich das am 
besten anstellen ?

Danke schon mal im voraus

Hans
Gast #785257
Lesenswert?

> Da es sich ja um eine Uhr handelt habe ich 3 Variablen stunden, minuten
> und sekunden. Diese habe ich dann als static gesetzt (global geht ja
> nur in einem .c File ?),

Was genau meinst du damit? Global heißt, daß es global, also überall 
verfügbar ist. Das gilt aber nicht, wenn du sie static machst. Nach 
deiner Beschreibung scheinst du es genau umgekehrt machen zu wollen.

> da ich mehrere "ausgelagerte" Funktionen in .c Files habe die die
> Uhrzeit-Variablen verändern bzw. benutzen (Uhrzeitstellen, eine
> Interruptroutine und die Ausgabefunktion ). Da ich die Variablen in
> Headerfiles drin hab, meckert das AVR-Studio nun andauernd über
> deklarierte aber nicht benutzte Variablen in main.

Statt das ellenlang zu erklären, hättest du auch ein paar Zeilen Code 
hinschreiben können, die es verständlicher erklären. Wenn du eine 
Variable im Header deklarierst, meckert der Compiler nicht.

> Jetzt meine Frage : Gibt es noch eine andere möglichkeit die 3
> Uhrzeit-Variaben aus den einzelnen Funktionen heraus zu ändern, ohne
> das ich die statischen Variablen benutzen muß ?

Wie kommst du überhaupt darauf, daß sie statisch sein müßten?
(Firma: O.D.I.S.) #785259
Lesenswert?

Hallo Hans,

der C-Compiler includiert den Header in eine temporäre Datei. Diese wird 
dann erst übersetzt.

Wenn Du also schreibst

clock.h:
1
int iHour, iMinute, iSecond;
2

3
void setClock();
4
void getClock();

und in main:
1
#include "clock.h"
2

3
int main()
4
{
5
...
6
    setClock();
7
    getClock();
8
}

dann versteht der Compiler in tempMain.c:
1
int iHour, iMinute, iSecond;
2

3
int main()
4
{
5
...
6
    setClock();
7
    getClock();
8
}

und das in jeder Datei die den Header anzieht.

Du mußt schreiben:

clock.h:
1
extern int iHour, iMinute, iSecond;
2

3
void setClock();
4
void getClock();

und in clock.c:
1
static int iHour, iMinute, iSecond;
2

3
void setClock()
4
{
5
}
6

7
void getClock()
8
{
9
}

und in main.c die Variante von ganz oben (das was Du eigentlich dem 
Compiler sagen wolltest).

Gruß

Olaf
#785310
Lesenswert?

Olaf Dreyer wrote:

Du hast so schön angefangen das zu erklären

> und in clock.c:
> static int iHour, iMinute, iSecond;

Fast. Ohne das static.

static an dieser Stelle bedeutet, dass die Variablen nur in
diesem File 'clock.c' bekannt sind. Daher kannst du dich dann
von anderen *.c nicht auf diese Variablen beziehen, weil der
Compiler dafür sorgt, dass diese Namen 'iHour, iMinute, iSecond'
ausserhalb von clock.c ganz einfach nicht existieren.
Gast #785630
Lesenswert?

Super, danke für die Antworten. Eine Frage habe ich noch, es ist leider 
einiges doch manchmal sehr unverständlich ( Obwohl ich schon 2 
verschiedene Bücher zu C gelesen habe)

>static an dieser Stelle bedeutet, dass die Variablen nur in
>diesem File 'clock.c' bekannt sind. Daher kannst du dich dann
>von anderen *.c nicht auf diese Variablen beziehen

Wenn ich dann jetzt in einem andern .c File die Variablen dann verwende, 
muss die in dem anderen .c File dann auch noch mal deklarieren oder 
reicht einmal ?
#785643
Lesenswert?

Hans Melten wrote:

> Wenn ich dann jetzt in einem andern .c File die Variablen dann verwende,
> muss die in dem anderen .c File dann auch noch mal deklarieren oder
> reicht einmal ?

Deklarieren musst du sie jedesmal, wenn du sie verwendest.
Aber es darf nur eine Definition geben


a.c
****
1
extern int xyz;     // <-  das ist durch das extern eine Deklaration
2
                    // es besagt, dass es irgendwo eine Variable
3
                    // namens xyz gibt. Wo genau interessiert hier
4
                    // nicht. Der Compiler will nur wissen, dass
5
                    // es sie gibtund dass sie ein int ist
6

7
void foo()
8
{
9
  xyz = 5;          // ansonsten könnte man die Variable hier ja
10
                    // nicht verwenden
11
}

b.c
****
1
            // Eine Variable die irgendwo existiert, ist aber zuwenig.
2
            // Irgendwann muss ins kalte Wasser gesprungen werden,
3
            // und die Variable xyz muss tatsächlich irgendwo
4
            // definiert werden.
5
            // Warum nicht hier?
6

7
int xyz;    // hier wird die Variable xyz tatsächlich erzeugt.
8
            // Das ist eine Definition. Egal wieviele andere
9
            // *.c Files mittels extern auf eine Variable
10
            // xyz verweisen, hier ist diese Variable tatsächlich
Gast #785788
Lesenswert?

Hallo,

man sollte sich klar machen, dass es in C keine globalen Variablen 
gibt. Die haben immer nur file scope, das heißt, sie sind nur dort 
bekannt, wo sie in der Datei stehen. Grob gesagt.

Curtis.
#785869
Lesenswert?

Curtis wrote:
> Hallo,
>
> man sollte sich klar machen, dass es in C keine globalen Variablen
> gibt. Die haben immer nur file scope, das heißt, sie sind nur dort
> bekannt, wo sie in der Datei stehen. Grob gesagt.
>

Na ja. So würde ich das eher nicht ausdrücken.

Wenn schon, dann läuft es in heutigem C auf die Regelung
hinaus: Verwendet werden kann nur, was auch bekannt ist.
Und wenn es nur eine Deklaration ist, die etwas bekannt macht.

Das mit 'immer file scope' stimmt so schon mal gar nicht.
Es sei dann du verstehst unter scope etwas anderes als der
C-Standard.
Aber in C hat alles erst mal globalen Scope, es sei denn
es ist mittels static auf einen File Scope begrenzt. Globaler
Scope bedeutet, dass jede andere Compilation Unit nach Gutdünken
Funktionen und Variablen durch eine Deklaration referenzieren kann
die in einer anderen Compilation Unit definiert sind. Erst durch
static lässt sich diese externe Referenzierung verhindern. Man
könnte also durchaus sagen: Erst mal ist alles global. Um eine globale
Funktion und/oder Variable zu benutzen, genügt eine Deklaration
und man hat den Fuss in der Türe.
Gast #785988
Lesenswert?

> Wenn schon, dann läuft es in heutigem C auf die Regelung
> hinaus: Verwendet werden kann nur, was auch bekannt ist.

Das gilt aber auch nur für Variablen. Funktionen läßt es dich auch 
benutzen, wenn sie eigentlich unbekannt sind.
#786477
Lesenswert?

Rolf Magnus wrote:
>> Wenn schon, dann läuft es in heutigem C auf die Regelung
>> hinaus: Verwendet werden kann nur, was auch bekannt ist.
>
> Das gilt aber auch nur für Variablen. Funktionen läßt es dich auch
> benutzen, wenn sie eigentlich unbekannt sind.

Ja, leider :-)
Gibt es eigentlich Bestrebungen seitens des Standard-Gremiums,
hier eine Änderung zu machen?

Glauben tu ichs nicht, aber die Hoffnung stirbt zuletzt.
Moderator Persönliche Seite #786490
Lesenswert?

Karl heinz Buchegger wrote:

> Gibt es eigentlich Bestrebungen seitens des Standard-Gremiums,
> hier eine Änderung zu machen?

Die Benutzung einer nicht deklarierten Funktion (impliziter
Ergebnistyp "int" und nicht spezifizierte Parameterliste) ist
ein hysterisches Fietscher und meiner Meinung nach ohnehin nicht
vom Standard abgedeckt.

Die Benutzung von Funktionen mit "K&R"-Deklaration (nicht-
prototypische Deklaration) ist vom C99-Standard als "obsolescent"
bezeichnet und damit potenzieller Kandidat, mal aus dem Standard
rauszufliegen.
Moderator Persönliche Seite #786493
Lesenswert?

Jörg Wunsch wrote:

> Die Benutzung einer nicht deklarierten Funktion (impliziter
> Ergebnistyp "int" und nicht spezifizierte Parameterliste) ist
> ein hysterisches Fietscher und meiner Meinung nach ohnehin nicht
> vom Standard abgedeckt.

Gefunden, im Vorwort von ISO/IEC 9899:1999:

5 This second edition cancels and replaces the first edition, ISO/IEC
  9899:1990, as amended and corrected by ISO/IEC 9899/COR1:1994,
  ISO/IEC 9899/AMD1:1995, and ISO/IEC 9899/COR2:1996. Major changes
  from the previous edition include:

  [...]
  -- remove implicit function declaration
Persönliche Seite #786524
Lesenswert?

Hi,

ich würde der einfachheit wegen ein struct vorschlagen.
1
struct timestruct
2
{
3
  int hour;
4
  int minute;
5
  int second;
6
};
7

8
timestruct time;
9

10

11
time.hour = 23;
12
time.minute = 59;
13
time.second = 59;

Der grosse Vorteil ist die sehr einfache Erweiterbarkeit, und die 
Übersichtlichkeit bleibt immer erhalten. Einfach
1
int day, int month, int milliseconds
 etc. in das struct und fertig.

Aisserdem macht dir z.B. der DevC als Editor entsprechende Vorschläge.



Hoffe mich nun nicht vertippt zu haben :-)


VG,
/r.
Gast #787271
Lesenswert?

Danke nochmals für die Zahlreichen Tips.

Einmal brauche ich aber noch eure Hilfe.
Und zwar geht um das OCR1A :
Ich habe eine config.h eingerichtet, wo ich wichtige Werte als #define 
gesetzt habe, unter anderem für den OCR1A mit #define UEBERLAUF 39999.
Wenn ich aber jetzt in meiner Timerroutine OCR1A = UEBERLAUF; eintrage, 
meckert WinAVR, das UEBERLAUF nicht deklariert ist.
Defines gelten doch überall im Programm ?? Andere defines Funktionieren 
Problemlos, wieso OCR1A nicht ? Liegt es daran das es ein 16Bit Reister 
ist ?
Gast #787550
Lesenswert?

Habe den mega8, der hat doch das Register.
Ich hab jetzt mal ein mini-programm geschrieben mit dem define und der 
extra datei und auch da meckert er das nichts definiert ist.
Kannst Du dir das bitte mal anschauen ?

Vielleicht habe ich ja Mist gebaut, aber dann bitte nicht hauen ;-)
Angehängte Dateien:
Moderator Persönliche Seite #787611
Lesenswert?

Ich sehe nicht, wo die Datei timerinit.c ein #include "config.h"
machen würde.  Woher bitte soll der Compiler beim Compilieren
von timerinit.c dann UEBERLAUF kennen?

Wenn du das korrigierst geht es bis auf:
1
avr-gcc -mmcu=atmega8 -Wl,-Map=probier_hier.map main.o timerinit.o     -o probier_hier.elf
2
main.o: In function `main':
3
/tmp/x/probier_hier/default/../main.c:8: undefined reference to `Timer_init'

Timer_init() ist was anderes als Timer1_init(). ;-)
Gast #788031
Lesenswert?

Ohje, das war wohl noch zu früh...
Mal abgesehen vom falschen Funktionsaufruf.

Ich hatte verstanden wenn ich die config.h einmal in main.c aufrufe 
reicht das.
Also muss die config für jede .c Datei aufgerufen werden, wo das define 
verwendet wird ?

In meinen C-Büchern steht leider nix über Programme mit mehreren Dateien 
und wie man sowas alles einbindet :-/
#788043
Lesenswert?

Hans Melten wrote:
> Also muss die config für jede .c Datei aufgerufen werden, wo das define
> verwendet wird ?
Tja, woher sonst soll der Compiler von dem Makro wissen? Du musst immer 
daran denken, dass der Compiler immer nur eine einzige Source-Datei 
sieht. Die anderen Dateien, die zum Projekt gehören, sind ihm in dem 
Moment völlig egal. Der Compiler bearbeitet jede einzelne Source-Datei 
so, als wäre sie die einzige auf der Welt. Erst der Linker macht aus den 
einzelnen Objekten, die der Compiler ausspuckt, ein zusammenhängendes 
Programm. Bis zu dem Zeitpunkt haben die einzelnen Dateien nichts 
miteinander zu tun. Dementsprechend muss alles, was der Compiler wissen 
muss, auch in der betreffenden Sourcedatei drinstecken bzw. vom 
Präprozessor über #include in das, was der Compiler letztendlich 
vorgesetzt bekommt, eingebaut werden.
Moderator Persönliche Seite #788075
Lesenswert?

Hans Melten wrote:

> Ich hatte verstanden wenn ich die config.h einmal in main.c aufrufe
> reicht das.

Scheint so, dass es mal Zeit wäre für einen Wiki-Artikel, der die
Funktion des Präprozessors erläutert...  (Solche Fragen wie deine
tauchen einfach immer wieder auf.)

Dein grundlegender Denkfehler ist, dass du config.h aufrufen
würdest.  “include” heißt ja weiter nichts als ,,zieh den Text
der Datei hier rein''.  Das Ergebnis der gesamten Kette einer
Quelldatei und all ihrer include-Dateien ist das, was der
C-Standard dann etwas hochtrabend klingend eine “compilation unit”
nennt: der C-Quelltext, der vom Compiler auf ein Mal compiliert
wird.

Der Präprozessor ist ein reiner Textverarbeiter.  Er nimmt sich
alle Zeilen, die mit # beginnen und such darin nach Anweisungen
für sich.  Bei einem #include wird die entsprechende Datei eingefügt.
Der Rest des durchlaufenden Textes wird noch auf C-Bezeichner hin
überprüft um zu schauen, ob der entsprechende Bezeichner zuvor mittels
#define als Makro definiert worden war.  Wenn dem so ist, wird er im
laufenden Text durch die rechte Seite des Makros substituiert.
Gast #788101
Lesenswert?

>Scheint so, dass es mal Zeit wäre für einen Wiki-Artikel, der die
>Funktion des Präprozessors erläutert

Ja, ich hätte nichts dagegen gehabt. Die Anfänge sind halt manchmal 
schwer ...

Das das #include nur den Text ersetzt hatte ich verstanden, nur halt 
nicht, das es nicht reicht einmal eine config.h aufzurufen.
Sondern das in jeder .c Datei auch wieder die config aufgerufen werden 
muß.

Von oben her hatte ich es so verstanden, das alle C-Dateien einfach 
hintereinander gereiht werden und das dann das, was die vorherige c. 
Datei schon kennt, die nächste c. Datei automatisch auch kennt.
Moderator Persönliche Seite #788111
Lesenswert?

Hans Melten wrote:

> Von oben her hatte ich es so verstanden, das alle C-Dateien einfach
> hintereinander gereiht werden

Nein, jede wird für sich separat übersetzt.  Die sich daraus
ergebenden (verschieblichen) Objektdateien werden dann vom Linker
zusammengefügt, wobei alle bis dahin offenen externen Referenzen
aufgelöst werden.

Es gibt allerdings in der Tat Compiler, die wie von dir beschrieben
vorgehen.  Die müssten dann aber, wenn sie konform zum C-Standard
sein wollen, zwischen den einzelnen C-Dateien die Inhalte aller
bereits gesehenen nicht-globalen Objekte und Funktionen und auch
aller Includes wieder ,,vergessen''.
Gast #788266
Lesenswert?

Ich arbeite lange schon mit folgender Struktur:

Alle c-Dateien haben nur EINEN include, nämlich #include "Main.h"

auch die Main.c hat nur diesen EINEN include-Hinweis

die Main.h hat dann alle anderen "includes", auch die eigenen anderen 
h-Dateien

z.B.

#include <avr/io.h>
#include <avr/pgmspace.h>
#include <inttypes.h>
#include <avr/interrupt.h>
#include <stdlib.h>


#include "Midi.h"
#include "Wasserspiele.h"
#include "Klangspiele.h"

damit wird alles übersichtlich, in den h-Dateien stehen Tabellen, 
Definitionen, Funktionsverweise, Variablen usw.

Das funktioniert gut und ist auch logisch -- oder?
#788279
Lesenswert?

@ Jens-Erwin (Gast)

>Alle c-Dateien haben nur EINEN include, nämlich #include "Main.h"

Eher schlecht.

>Das funktioniert gut und ist auch logisch -- oder?

Nöö. Wenn du in einem grossen Projekt nur EINE Datei änderst, muss ALLES 
neu übersetzt werden. Nicht gut.

Ergo. Jede C-Datei hat nur die includes, die WIRKLICH gebraucht werden.

MfG
Falk
Gast #788301
Lesenswert?

Das sind schon auch große Projekte aber eben nur für uC. Für einen uC 
wie den AVR ist das übersetzen aller Dateien doch gar kein Problem.

Außerdem ging es ja um eine gewisse Übersichtlichkeit für Anfänger und 
in einen AVR z.B. passt gar nicht so viel rein. Da kann schon alles 
übersetzt werden. Jedenfalls wird so nie gemeckert, dass der Compiler 
irgendwas nicht finden würde ...
Persönliche Seite #788384
Lesenswert?

Jens-Erwin wrote:
> Das sind schon auch große Projekte aber eben nur für uC. Für einen uC
> wie den AVR ist das übersetzen aller Dateien doch gar kein Problem.

Der AVR übersetzt überhaupt nichts!

> Außerdem ging es ja um eine gewisse Übersichtlichkeit für Anfänger und
> in einen AVR z.B. passt gar nicht so viel rein. Da kann schon alles
> übersetzt werden. Jedenfalls wird so nie gemeckert, dass der Compiler
> irgendwas nicht finden würde ...

Und mit der Codegröße hat das auch nichts zu tun.

Aber das Kompilieren dauert, gerade bei großen Projekte, wesentlich 
länger wenn 90% der Zeit unnütze Headerfiles abgearbeitet werden müssen.
Gast #788952
Lesenswert?

>> Das sind schon auch große Projekte aber eben nur für uC. Für einen uC
>> wie den AVR ist das übersetzen aller Dateien doch gar kein Problem.
>
> Der AVR übersetzt überhaupt nichts!

Ich glaube, es war eher so gemeint: "Das Übersetzen für den AVR ist kein 
Problem". Gemeint war wohl, daß AVR-Projekte klein genug sind, um auch 
mit vielen Headern schnell genug übersetzt werden zu können.
Das würde mit meiner Arbeitsweise aber nur bedingt gelten. Ich lasse 
meinen Code sehr oft durch den Compiler laufen (auch öfter, als ich es 
flashen würde), nur um zu sehen, ob nicht ein Flüchtigkeitsfehler drin 
ist. Wenn da praktisch nach jeder kleinen Änderung immer erst das 
gesamte Projekt übersetzt werden müßte, würde mir das zu lange dauern. 
Dann könnte ich mir die tolle Aufteilung auch sparen und gleich alles in 
ein riesiges C-File schreiben.

> Und mit der Codegröße hat das auch nichts zu tun.

Doch schon. Wenn in den Prozessor nicht viel reinpasst, bleibt 
tendenziell der Quellcode kleiner und kann vom Compiler schneller 
übersetzt werden, so die Theorie. ;-)
Gast #789251
Lesenswert?

Genau so wollte ich es verstanden haben .... Danke

Es ist schon übersichtlicher quasi "ein" C-File in mehrere "kleinere" 
Files aufzuteilen, um damit die einzelnen Themen übersichtlicher zu 
bearbeiten und vielleicht auch in andere (ähnliche) Projekte zu 
übertragen.

Mir hat's jedenfalls geholfen und hilft noch ...
Gast #791413
Lesenswert?

Jedes einzelne File ist compilierbar -- Alt+F7

auch wenn alle c-Dateien auf eine h-Datei, die wiederum andere h-Dateien 
includieren kann, zugreifen ...

--- das spart wirklich Zeit -- toll


Dann ist diese Methode GENIAL

-- Idee hat mir übrigens vor Jahren mal jemand aus dem Forum empfohlen 
---

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren