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
> 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?
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.
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 ?
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
externintxyz;// <- 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
voidfoo()
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
intxyz;// 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
Ja, danke.
Habe es jetzt raus.
War eine schwierige Geburt, aber dank Deiner Hilfe habe ich es doch noch
hinbekommen.
Das Programm läuft jetzt einwandfrei !
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.
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.
> 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.
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.
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.
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
Ich mach hier mal die Ingrid...
Jörg Wunsch wrote:
> -- remove implicit function declaration
Folgerichtig warnt GCC bei -std=gnu99 und -std=c99 auch ohne jegliche
-W-Option darüber.
Hi,
ich würde der einfachheit wegen ein struct vorschlagen.
1
structtimestruct
2
{
3
inthour;
4
intminute;
5
intsecond;
6
};
7
8
timestructtime;
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
intday,intmonth,intmilliseconds
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.
Das geht in C so nicht. Eine struct bildet in C keinen eigenen
Namen ohne das Schlüsselwort "struct" (anders als in C++).
Einen wirklichen Mehrwert außer mehr Schreibarbeit sehe ich allerdings
darin nicht.
ok, dann kommt noch nen typedef mit dazu :-)
Arbeite meist mit pointern, structs brauche ich selten, daher muss ich
bei der syntax oft eben nachsehen ...
Daten, die einen gemeinsamen Nenner haben, sollte man aber immer
zusammenfassen, allein der Lesbarkeit halber.
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 ?
Hans Melten wrote:
> Wenn ich aber jetzt in meiner Timerroutine OCR1A = UEBERLAUF; eintrage,> meckert WinAVR, das UEBERLAUF nicht deklariert ist.
Hast du denn auch ein
1
#include"config.h"
in deiner Applikation drin?
> Defines gelten doch überall im Programm ?
Nicht überall, sondern ab dem Moment, da der Compiler das #define
,,gesehen'' hat.
Ja, ich hab das config.h direkt am Anfang von main.c vor allen anderen
Header-Dateien.
Andere defines in verschiedenen Modulen funktionieren auch, nur eben
OCR1A nicht.
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 ;-)
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:
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 :-/
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.
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.
>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.
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''.
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?
@ 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
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 ...
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.
>> 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. ;-)
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 ...
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
---