Hallo!
Eine einfache und kurze Frage: ;)
Muss ich beim Programmstart alle meine Variablen mit 0 initialisieren
oder ist das überflüssig? Soweit ich weiß, steht da am Anfang sowieso
überall 0 drin. Was ist guter Codestil? ^^
Danke!
öhm
öhm schrieb:> Muss ich beim Programmstart alle meine Variablen mit 0 initialisieren> oder ist das überflüssig? Soweit ich weiß, steht da am Anfang sowieso> überall 0 drin. Was ist guter Codestil? ^^
kommt wohl auf die Programiersprache an. Bei C werden globale variabel
mit 0 initialisieren. Lokale aber nicht.
Ausgehend von C/C++:
Globale Variablen werden mit 0 initialisiert.
Lokale variablen bekommen den Wert den Du ihnen zuweist. Wenn du nichts
zuweist, also ein "int x;" dann steht da irgendwas drin!
Aus eigener erfahrung empfehle ich dir:
Initialisiere jede Variable mit einem Startwert (ob 0 oder 1337 ist
egal), dann hast du nach dem Start immer den selben definierten zustand.
Wenn du keine initialisierung vornimmst ist nicht garantiert das nach
jedem start das selbe drin steht, das ist glückssache.
Ohne initialisierung kannst du z.B. bei Bool-Variablen das Problem
haben, das ein Programm auf der einen Plattform funktioniert (z.B.
FreeBSD) und auf der anderen Plattform (z.B. Windows) funktioniert es
nicht, weil jede Plattform einen anderen "default"-Startwert in die
variable wirft, und dann finde den Fehler mal.
Initialisiere einfach, das tut nicht weh, schaft definierte zustände
nach dem Starten und erleichtert die Fehlersuche.
Grüße Kaj
Programmiersprache C. Logo ;)
Aha. Wenn es also nicht garantiert wird, dass da immer 0 drinsteht. Dann
ist wohl guter Stil, dass man vorher alles auf 0 setzt, richtig?
Wenn der Compiler das von Haus aus macht, dann wird er diesen
zusätzlichen Code automatisch wegoptimieren oder?
Soweit meine Gedanken.
öhm schrieb:> Aha. Wenn es also nicht garantiert wird, dass da immer 0 drinsteht. Dann> ist wohl guter Stil, dass man vorher alles auf 0 setzt, richtig?
Es IST garantiert für alle Variablen mit "static storage". Das sind alle
globale, und alle statisch lokale Variablen.
öhm schrieb:> Programmiersprache C. Logo ;)>> Aha. Wenn es also nicht garantiert wird, dass da immer 0 drinsteht. Dann> ist wohl guter Stil, dass man vorher alles auf 0 setzt, richtig?
Das kommt drauf an, wie schon gesagt.
Globale Variablen werden auf 0 initialisiert. Und das ist auch
garantiert.
Wenn du selber sie mit 0 initialisierst, dann ist das ok. Allerdings
läuft man auch schon mal Gefahr, dass man vor lauter 0-initialisierten
Variablen diejenigen, die eben nicht mit 0 initialisiert werden schon
auch mal übersieht.
Codemässig macht es allerdings keinen UNterschied. Schreibst du keine
Initialisierung hin, dann ergänzt sie der COmpiler stillschweigend.
Bei globalen Variablen. Bei funktionslokalen Variablen sieht die Sache
anders aus.
Nu scheint es doch garantiert zu sein, dass da 0 drin steht grmf... ^^
2 Fragen noch: :)
1)
Könnte mir bitte noch jemand sagen, ob 0 Initialisierungen vom compiler
wegoptimiert werden, um speicherplatz zu sparen?
2)
Ich hab in ner *.h nen globales struct:
struct test
{
int x;
...
}test;
In ner *.c will ichs initialiseren:
test.x = 0;
...
Das doch soweit ok? Oder initialisiert ihr auf ne feinere Art?
gruß
öhm
öhm schrieb:> 1)> Könnte mir bitte noch jemand sagen, ob 0 Initialisierungen vom compiler> wegoptimiert werden, um speicherplatz zu sparen?
nein, das würde ja der aussagen wiederprechen das sie mit 0 Initalisiert
werden.
> 2)> Ich hab in ner *.h nen globales struct:
in einer header Datei sollte man keine Variabel anlegen! Du bekommst
probleme wenn du diese Header datei in einer 2. C datei includierst.
Karl Heinz Buchegger schrieb:> Globale Variablen werden auf 0 initialisiert. Und das ist auch> garantiert.
Wage ich zu bezweifeln, dass das bei jedem Compiler bzw. Zielsystem so
ist. Ich hab hier mindestens ein Gegenbeispiel.
Man kann die Variablen aber direkt bei der Definition vorbelegen, also
so:
int meineVar = 4711;
int meineVar2 = 0;
Steel schrieb:> Wage ich zu bezweifeln, dass das bei jedem Compiler bzw. Zielsystem so> ist. Ich hab hier mindestens ein Gegenbeispiel.
dann nenn es uns doch.
Wenn der Compiler es nicht macht, dann ist es kein brauchbarer
C-Compiler. Dann könnte man auch anzweifeln das er aus 1+1 2 macht.
Peter II schrieb:> in einer header Datei sollte man keine Variabel anlegen! Du bekommst> probleme wenn du diese Header datei in einer 2. C datei includierst.
? Hatte ich bis jetzt keine Probleme mit. Genügt doch einfach:
#ifndef ATMEGA32_CONFIG_H_
#define ATMEGA32_CONFIG_H_
in die *.h zu setzen.
Arbeite mit meinem globalen struct in 3 verschiedenen *.c files und
alles läuft ohne probleme.
Steel schrieb:> Wage ich zu bezweifeln, dass das bei jedem Compiler bzw. Zielsystem so> ist. Ich hab hier mindestens ein Gegenbeispiel.
Dann ist dieses "Gegenbeispiel" schlicht kaputt, denn der Standard
verlangt diese Null-Initialisierung.
öhm schrieb:> Könnte mir bitte noch jemand sagen, ob 0 Initialisierungen vom compiler> wegoptimiert werden, um speicherplatz zu sparen?
Naja meist ist der RAM ja kleiner als der ROM, und zwar deutlich, ist
also nicht so schlimm. Ob es wirklich einen Unterschied macht kann man
am besten herausfinden wenn man mal ein kleines Programm schreibt und
mal nicht, mal mit 0 und mal mit 5 initalisiert, und dann die Größe des
ROMs vergleicht.
öhm schrieb:> Peter II schrieb:>> in einer header Datei sollte man keine Variabel anlegen! Du bekommst>> probleme wenn du diese Header datei in einer 2. C datei includierst.>> ? Hatte ich bis jetzt keine Probleme mit. Genügt doch einfach:> #ifndef ATMEGA32_CONFIG_H_> #define ATMEGA32_CONFIG_H_
nein das hilft dagen nicht. Weil jede C Datei einzeln übersetzt wird
> Arbeite mit meinem globalen struct in 3 verschiedenen *.c files und> alles läuft ohne probleme.
dann hast du 3 mal diese Variable mit 3 Verschienden Adressen.
öhm schrieb:> ? Hatte ich bis jetzt keine Probleme mit. Genügt doch einfach:> #ifndef ATMEGA32_CONFIG_H_> #define ATMEGA32_CONFIG_H_>> in die *.h zu setzen.
Include-Guards haben rein gar nichts mit "in einer 2. C-Datei
inkludieren" zu tun. Sie verhindern nur das mehrfache Einbinden
innerhalb ein und der selben C-Datei.
öhm schrieb:> Arbeite mit meinem globalen struct in 3 verschiedenen *.c files und> alles läuft ohne probleme.
Und das liegt wiederum daran, wie dein Compiler/Linker sowas handhabt.
"läuft ohne probleme" heißt hier nicht "korrekt so".
Peter II schrieb:> dann hast du 3 mal diese Variable mit 3 Verschienden Adressen.
Wie ist es dann möglich, dass ich den Wert der Variable in einem *.c
file ändere und die Änderung in den anderen 2 *.c files übernommen wird,
wenn die adresse unterschiedlich ist?
öhm schrieb:> Nu scheint es doch garantiert zu sein, dass da 0 drin steht grmf... ^^
Ja, für GLOBALE Variablen, die Du nicht initialisierst.
LOKAL steht "irgendwas" drin.
Grüße
Peter II schrieb:>> Arbeite mit meinem globalen struct in 3 verschiedenen *.c files und>> alles läuft ohne probleme.>> dann hast du 3 mal diese Variable mit 3 Verschienden Adressen.
Kommt auf den Compiler/Linker an. Der GCC z.B. legt aus historischen
Gründen mehrfache Definitionen gleichen Namens auf die selbe Adresse.
Stefan Ernst schrieb:> Und das liegt wiederum daran, wie dein Compiler/Linker sowas handhabt.> "läuft ohne probleme" heißt hier nicht "korrekt so".
"Korrekt so" wäre also:
1.h:
struct test
{
}test;
2.h:
extern test;
Oder wie?
Stefan Ernst schrieb:> Dann ist dieses "Gegenbeispiel" schlicht kaputt, denn der Standard> verlangt diese Null-Initialisierung.
Im ebmedded Bereich hält sich nunmal nicht jeder Compiler strikt an den
Standard.
Steel schrieb:> Stefan Ernst schrieb:>> Dann ist dieses "Gegenbeispiel" schlicht kaputt, denn der Standard>> verlangt diese Null-Initialisierung.>> Im ebmedded Bereich hält sich nunmal nicht jeder Compiler strikt an den> Standard.
Mag sein.
Allerdings ist das Ausnullen eines Speichers oder Speicherbereiches beim
Programmstart trivial und verschlingt jetzt auch nicht massig Code.
Von daher würde ich dann schon sagen
> Dann ist dieses "Gegenbeispiel" schlicht kaputt
eine Variable 'dummy' existiert schlicht und ergreifend nicht.
Wohl aber eine Variable namens 'test'. Und weil dieses 'test' vom Typus
'struct testS' ist, hat es auch einen Member namens 'dummy'. Daher
test.dummy
Und in 1.c muss selbstverständlich noch ein #include auf 1.h rein. Woher
soll denn der Compiler beim compilieren von 1.c sonst wissen, was ein
struct testS ist?
Abgesehen davon:
Ja, genau so macht man das.
Karl Heinz Buchegger schrieb:> Abgesehen davon:> Ja, genau so macht man das.
Hab ich endlich mal was richtig gemacht. Unglaublich ^^ Oder moment,
kann mich mal jemand picksen, damit ich aufwach? xDD
Ja ich meinte test.dummy! Allerdings meckert der compiler:
undefined reference to "test"
Ahhh... ich hab den Fehler raus. Hatte geschrieben
1
1.c:
2
voidInit()
3
{
4
structtestStest={0};
5
}
6
7
anstatt:
8
9
1.c:
10
11
structtestStest={0};
12
13
voidInit()
14
{
15
}
Wobei dann die Frage ensteht ob ich das void init überhaupt noch
brauche.
Noch eine Frage:
Sehe auch öfters ein typdef bei den structs. Ist das im embedded Bereich
sinnvoll?
Wenn ja, wie würde dann die Syntax für mein oberes Beispiel aussehen?
öhm schrieb:> Noch eine Frage:>>> Sehe auch öfters ein typdef bei den structs. Ist das im embedded Bereich> sinnvoll?
Das eine hat ja mit dem anderen nichts zu tun.
Wenn es dir zu blöd ist, dauernd 'struct testS' schreiben zu müssen,
dann deklarierst du dir eben mit einem typedef einen neuen Datentyp, zb
myTestS, der ein anderen Name für ein 'struct testS' darstellt
1
typedefstructtestSmyTestS;
Jetzt hast du einen neuen Datentyp vereinbart, den du in weiterer Folge
benutzen kannst. Zb um damit Variablen zu definieren oder deklarieren
...
1
myTestStest;
... ohne dauernd 'struct' schreiben zu müssen.
> Wenn ja, wie würde dann die Syntax für mein oberes Beispiel aussehen?
Schön langsam sind wir an einem Punkt angelangt, andem ich dich fragen
muss, ob denn dein C-Buch zu diesen Themen überhaupt nichts zu sagen
hat? Wenn ja (was ich mir nicht vorstellen kann), dann schmeiss es weg
und kauf dir ein Ordentliches, dein Lehrbuch taugt nichts.
Viel wahrscheinlicher ist es allerdings, dass du gar kein Buch hast. Und
in dem Fall muss ich dich fragen: Warum nicht? Wenn du denkst du kannst
eine Programmiersprache wie C durch Erfragen von anlassbezogenem
Achtelwissen in Foren erlernen, dann bist du schief gewickelt.
Peter II schrieb:> öhm schrieb:>> 1.c:>> void Init()>> {>> struct testS test = {0};>> }>> hier legst du eine funktionslokale Variabel an und verwendest nicht die> globale.
Ich möchte ja das globale struct initialisieren. Denke es müsste so
sein:
[c]
1.c:
struct testS test;
void Init ()
{
test.dummy = 0;
}
öhm schrieb:> Ich möchte ja das globale struct initialisieren. Denke es müsste so> sein:
.... initialisieren .....
>
1
>1.c:
2
>
3
>structtestStest;
4
>
5
>voidInit()
6
>{
7
>test.dummy=0;
8
>}
9
>
Das hier ist streng genommen keine Initialisierung mehr. Das ist eine
Zuweisung!
Vor Aufruf der Funktion Init() hat test.dummy den Wert 0. Als globale
Variable wird sie automatisch auf diesen Wert initalisiert. Dann rufst
du Init auf und weißt test.dummy einen Wert zu (der in diesem Fall
ebenfalls 0 ist).
Initialisierungen gibt es immer nur ein einziges mal. Variablen werden
initialisiert (wenn überhaupt), wenn die Variablen erzeugt werden, wenn
sie geboren werden. Initialisierungen werden daher immer bei der
Definition der Variable angeführt. Alles andere danach kann dann nur
noch eine Zuweisung sein.
In C gibt es ein paar kleinere Feinheiten, die auf dem Unterschied
Initialisierung-Zuweisung aufbauen. Von daher ist es wichtig, diesen
Unterschied zu kennen! Zum Beispiel können 'const' markierte Dinge nur
initialisiert werden, nicht jedoch zugewiesen.
1
constinti=5;// ist ok. Das ist eine Initialisierung
Verstehe.
@Karl Heinz Buchegger: Danke :)
Welchen Vorteil hat dieser Code:
1
structtestStest={0};
2
3
intmain()
4
{
5
...
6
}
vor diesem:
1
structtestStest;
2
3
4
voidInit(void)
5
{
6
test.dummy=0;
7
}
Wird wohl Speicher eingespart? Meine frage deshalb, weil wenn ich
größeren structs Werte zuweisen möchte, dann währe meiner Ansicht nach
alles in einer Init() besser und übersichtlich aufgehoben....
öhm schrieb:> void Init (void)> {> test.dummy = 0;> }
eigentlich hat die init funktion nur nachteile:
Die initalisierung auf 0 wird ja sowiso gemacht. In der Init
überschreibst du also die werte. Damit ist es schon mal doppelte code.
Wenn du die init im laufenden Betrieb nicht aufrufst, dann würde ich sie
weglasen.
Das war nur ein kleines Beispiel. Es wird nicht nur 0 zugewiesen.
Ich habe drei *.c files. In allen gibts nen globales struct.
In meiner main würd ich halt gern schreiben:
int main
{
Init();
...
}
Und in dieser Init() würden dann alles auf die Startwerte gesetzt
werden.
Ansonsten müsste ich in jeder der drei files die initialiserung extra
durchführen... Das das problem.
öhm schrieb:> Und in dieser Init() würden dann alles auf die Startwerte gesetzt> werden.> Ansonsten müsste ich in jeder der drei files die initialiserung extra> durchführen... Das das problem.
Die Frage ist halt, inwiefern diese Initialisierungen für diese 'Module'
eine Privatangelegenheit sind, oder ob main() (im Grunde) davon wissen
muss, dass hier Initialisierungen durchzuführen sind.
Grundsätzlich: Je weniger du in main() wissen musst, zum Beispiel auch
darüber, dass du eine Funktion aufrufen musst, die erst mal eine gültige
Ausgangssituation herstellt, ... desto besser. Eine Funktion die man
nicht aufrufen muss, kann man auch nicht vergessen aufzurufen.
Werd mal etwas konkreter, was diese Strukturen angeht. Was beschreiben
die? Gehören die in irgendeiner Form zusammen? Gibt es da
Abhängigkeiten?
Denn
> In meiner main würd ich halt gern schreiben:
genau das möchte man nämlich eigentlich nicht 'gerne' tun.
Manchmal muss man diese Krot schlucken, weil es nicht anders geht. Aber
gerne macht man das nicht.
öhm schrieb:> Und in dieser Init() würden dann alles auf die Startwerte gesetzt> werden.
Wenn es globale Variablen sind und du es zur Laufzeit nie neu
initialisieren musst: nimm eine Initialisierung statt einer
Zuweisung. Das spart massig Code. Deine Zuweisung kann der
Compiler nicht optimieren, die wird einzeln Tippeltappeltour
durchlaufen. Bei einer Initialisierung dagegen speichert er nur
die Initialwerte als kompletten Block irgendwo ab und lädt die
entsprechenden RAM-Bereiche beim Start davon. Das ist also effektiv
genau ein memcpy(), was da ausgeführt werden muss. (Objekte, die
komplett nur mit Nullen vorbelegt werden müssen, müssen nicht einmal
kopiert werden, sondern sie werden mit etwas wie memset() auf Null
gesetzt.)
Wenn du wirklich auch zur Laufzeit wieder ganz von vorn anfangen
können musst, würde ich mir überlegen, wie man den Controller dann
durch einen vollständigen Reset schießen kann.
Stefan Ernst schrieb:> Peter II schrieb:>>> Arbeite mit meinem globalen struct in 3 verschiedenen *.c files und>>> alles läuft ohne probleme.>>>> dann hast du 3 mal diese Variable mit 3 Verschienden Adressen.>> Kommt auf den Compiler/Linker an. Der GCC z.B. legt aus historischen> Gründen mehrfache Definitionen gleichen Namens auf die selbe Adresse.
Ja, uninitialisierte Variablen werden in den "common" Block gelegt. Ist
wohl eine uralte Unix-Tradition aus der Zeit vor ANSI-C. Daher empfiehlt
sich bei GCC auch die Verwendung von -fno-common, um das zu verhindern.
Damit bekommt man dann Fehlermeldungen wenn derselbe Variablenname in
mehreren Quelldateien global definiert wird.
Ok langsam kommen wir auf den gleichen Nenner. ^^
Ich weiß jetzt wie ich das in meiner konkreten Situation zu machen
haben.
Ich nehme die Funktion aus der main raus und inizialisiere in den drei
*.c
Dateien, anstatt wie früher 100 Zuweisungen zu haben.
Eine Sache möchte ich allerdings nicht fallen lassen, nämlich die
Übersichtlichkeit. Ich möchte alle Startbedingungen auf einen Blick in
einer Datei haben, da an diesen Werten hin und wieder gedreht werden
muss.
Das würde ich dann über defines machen. Zum Beispiel:
def.h:
#define VELOCITY_MAX (200)
...
1.c:
struct testS test =
{
.Velocity_Max = VELOCITY_MAX,
...
}
Sieht soweit gut aus oder?
öhm schrieb:> Ich möchte alle Startbedingungen auf einen Blick in einer Datei haben,> da an diesen Werten hin und wieder gedreht werden muss.
Ein möglicher Ansatz ist deiner, wobei er praktisch die doppelte
Anzahl von Namen verursacht.
Ein anderer wäre es, sämtliche globalen initialisierten Variablen
in einer eigenen C-Datei abzulegen, in der dann auch die Initialwerte
stehen.
Hallo!
Ich möchte an dieser Stelle noch eine Frage anfügen:
Darf ich immer davon ausgehen, dass beim Programmstart alle timer,
interrupts etc register mit 0x00 beschrieben sind? Oder gibt es hier
auch
Ausnahmen?
gruß
öhm
Die Resetwerte der einzelnen SFRs sind im jeweiligen Manual aufgeführt
und haben nichts mit der C-Initialisierung zu tun. Nicht alle SFRs
werden beim Powerdown-Reset auf 0 gesetzt, siehe TWSR beim ATmega168.
öhm schrieb:> Darf ich immer davon ausgehen, dass beim Programmstart alle timer,> interrupts etc register mit 0x00 beschrieben sind?
Nein.
> Oder gibt es hier auch Ausnahmen?
Ja. Steht im Datenblatt des verwendeten Controllers. Evt. wurstelt der
Compiler da noch was rum, sollte dann aber irgendwo im Manual des
Compilers beschrieben sein.
öhm schrieb:> Ah, ich sehe grad im Datenblatt, dass unter jedem Register die "initial> values" eingetragen sind. Danke!>> Wie war das nochmals:>> X = undefined> N/A = ?
N/A
not available ... (Information) nicht verfügbar
not applicable ... macht in dem Zusammenhang keinen Sinn.
Es mag noch andere Verwendungen für diese Abkürzung geben, aber das sind
wohl die beiden häufigeren in unserem Metier.
öhm schrieb:> Wenn der Compiler das von Haus aus macht, dann wird er diesen> zusätzlichen Code automatisch wegoptimieren oder?
Erstmal eines: Der Compiler macht da garnix. Wenn überhaupt, dann macht
der Startup-Code irgendwas - oder auch nicht. Das hängt vom uC ab und
von der konkreten Toolchain und von einigen anderen Dingen. Manchmal hat
man im Startup-Code nix, manchmal ne generelle RAM-Ablöschung, manchmal
auch eine Kopierroutine, die die Variablen im RAM mit einem im Code
gespeicherten Datenblock initialisiert. Hat alles seine Vor- und
Nachteile.
Karl Heinz Buchegger schrieb:> Globale Variablen werden auf 0 initialisiert. Und das ist auch> garantiert.
Und bittesehr von WEM? Wer garantiert einem da was?
Nein, das ist überhaupt nicht garantiert, sondern hängt schlichtweg
davon ab, ob und was der konkret verwendete Startupcode macht. Wenn man
dort eine Routine für die RAM-Ablöschung drin hat, dann wird dort auch
der RAM abgelöscht. Sonst eben nicht. Drauf verlassen sollte man sich
nur dann, wenn man die Ablöscherei selber geschrieben oder wenigstens
überprüft hat.
Leute, wir sind hier bei Mikrocontrollern, gelle?
W.S.
W.S. schrieb:> Karl Heinz Buchegger schrieb:>> Globale Variablen werden auf 0 initialisiert. Und das ist auch>> garantiert.>> Und bittesehr von WEM? Wer garantiert einem da was?
Im C-Standard
6.2.4 $3
> An object whose identifier is declared with external or internal> linkage, or with the storage-class specifier "static" has static> storage duration. Its lifetime is the entire execution of the> program and its stored value is initialized only once,> prior to program startup.
sowie 6.7.8 $10
> [...]> If an object that has static storage duration is not> initialized explicitly, then:> — if it has pointer type, it is initialized to a null pointer;> — if it has arithmetic type, it is initialized to (positive> or unsigned) zero;> — if it is an aggregate, every member is initialized (recursively)> according to these rules;> — if it is a union, the first named member is initialized (recursively)> according to these rules.
Daß bei Nichteinhaltung des Standards alles möglich ist, ist ja wohl
klar und bedarf kaum des Aufhebens.
W.S. schrieb:> Leute, wir sind hier bei Mikrocontrollern, gelle?
Und?
Deswegen gelten die C-Regeln nicht mehr, oder wie ist das?
Wenn deine Compiler das nicht tun, dann sind sie keine C-Compiler
sondern compilieren irgendwas was so ähnlich aussieht wie C, es aber
nicht ist. Wenn deine Compiler/Linker einen Schalter haben, der in der
Runtime die geforderte 0-Initialisierung abschaltet, dann ist das nett,
kann aber kaum zur allgemeinen Regel erhoben werden.
Wenn ich mich nicht mehr darauf verlassen kann, was mir als
C-Programmierer im C-Standard zugesichert wird, worauf kann ich mich
dann überhaupt verlassen?
Ich muss euch beiden Recht geben. Der Standard garantiert, dass globale
Variablen mit Null initialisiert werden. Doch es gibt im
Mikrocontrollerbereich Compiler, die in einigen Punkten vom Standard
abweichen, weil diese bei Mikrocontrollern kontraproduktiv oder nicht
sinnvoll sind. Also kann man sich erst zu 100% darauf verlassen, nachdem
man das Handbuch des Compilers gelesen/überflogen hat (was man ja so
oder so tut, bzw. tun sollte).
Schon nur aus Gründen der Übersichtlichkeit und Verständlichkeit des
Codes initialisiere ich globale Variablen mit dem gewünschten Wert (auch
wenn das Null ist), wenn der Variable zwingend diesen Wert zugewiesen
werden muss. Ansonsten initialisiere ich die Variable nicht. Mache ich
grundsätzlich mit allen Variablen so.
Karl Heinz Buchegger schrieb:> Und?
Ach, Karl Heinz, das war einfach nur ein typischer W. S. Der Thread
war zwar schon lange durch, aber er muss natürlich auch noch was dazu
sagen. Ob er das überhaupt weiß und ob es richtig oder falsch ist,
spielt dabei eine nur sehr untergeordnete Rolle …
be stucki schrieb:> Doch es gibt im Mikrocontrollerbereich Compiler, die in einigen Punkten> vom Standard abweichen, weil diese bei Mikrocontrollern kontraproduktiv> oder nicht sinnvoll sind.
Die Initialisierung globaler Variablen ist jedoch ein derart
grundlegendes Prinzip von C, dass eine Toolchain, die das nicht
macht, sich auch nicht "C" nennen darf. Selbstverständlich hat eine
derartige Initialisierung in aller Regel auch im Umfeld von
Mikrocontrollern ihre Berechtigung und ist keineswegs kontraproduktiv.
(Einzelne Ausnahmen kann man sehr selten mal gebrauchen, siehe das
".noinit"-Feature in der avr-gcc/avr-libc-Toolchain, für Variablen,
deren Wert einen Reboot überleben soll, und deren initiale
Wertzuweisung an anderer Stelle als beim Startup erfolgen soll.)
> Schon nur aus Gründen der Übersichtlichkeit und Verständlichkeit des> Codes initialisiere ich globale Variablen mit dem gewünschten Wert (auch> wenn das Null ist)
Bei älteren GCC-Versionen war das übrigens wirklich kontraproduktiv:
damit hat man das entsprechende Objekt nämlich aus dem BSS raus und
ins Data reingeworfen, mit dem Effekt, dass dann für die Initialisierung
mit 0 zusätzlich Platz benötigt worden ist.
Außerdem: wenn du dich nicht auf die 0-Initialisierung verlassen
möchtest, woher nimmst du dann die Gewissheit, dass die explizite
Initialisierung (von nicht-"auto"-Variablen meine ich) denn noch
funktioniert? Vielleicht hat der ehrenwerte Tool-Hersteller ja diese
auch als "bei Mikrocontrollern kontraproduktiv" gleich mal weggelassen?
;-)
Jörg Wunsch schrieb:> Die Initialisierung globaler Variablen ist jedoch ein derart> grundlegendes Prinzip von C, dass eine Toolchain, die das nicht> macht, sich auch nicht "C" nennen darf.
Das ist mir bewusst, evt. ist mein Beitrag falsch rübergekommen. Er
bezog sich nicht nur auf die Null-Initialisierung globaler Variablen,
sondern dass es "C"-Compiler gibt, die nicht zu 100% dem C-Standard
entsprechen.
Jörg Wunsch schrieb:> Bei älteren GCC-Versionen war das übrigens wirklich kontraproduktiv:> damit hat man das entsprechende Objekt nämlich aus dem BSS raus und> ins Data reingeworfen, mit dem Effekt, dass dann für die Initialisierung> mit 0 zusätzlich Platz benötigt worden ist.
Solange ich genug Speicher habe, wäre mir das egal.
Jörg Wunsch schrieb:> Außerdem: wenn du dich nicht auf die 0-Initialisierung verlassen> möchtest, woher nimmst du dann die Gewissheit, dass die explizite> Initialisierung (von nicht-"auto"-Variablen meine ich) denn noch> funktioniert? Vielleicht hat der ehrenwerte Tool-Hersteller ja diese> auch als "bei Mikrocontrollern kontraproduktiv" gleich mal weggelassen?> ;-)
Ich würde mich darauf verlassen, wenn es denn nötig wäre. Ich
initialisiere alle Variablen, damit ich auch in 2 Monaten auch noch
weiss, dass der Inhalt der Variable beim Aufstarten zwingend Null (oder
sonst ein Wert) sein muss, damit mein Programm richtig funktioniert. Es
gibt solche Fälle, diese versuche ich natürlich immer zu vermeiden.
be stucki schrieb:> sondern dass es "C"-Compiler gibt, die nicht zu 100% dem C-Standard> entsprechen.
Selbstverständlich. Auch der GCC ist meines Wissens nicht komplett
C99-kompatibel (von C1x ganz zu schweigen). Der AVR-GCC ist schon
dahingehend nicht konform, dass sein "double" nur 32 bits groß ist
und damit den Minimalforderungen des Standards an ein double nicht
genügt (48 bits wären ausreichend, es müssen nicht zwingend 64 sein).
Aber das sind alles weit weniger wichtige Dinge als die Initialisierung
globaler und statischer Objekte, die seit jeher ein Bestandteil der
Sprache C war und ist.
Jörg Wunsch schrieb:> Der AVR-GCC ist schon dahingehend nicht konform, dass sein> "double" nur 32 bits groß ist und damit den Minimalforderungen> des Standards an ein double nicht genügt
Noch ne abschweifende Frage dazu: Im GCC double auf 64 Bits zu setzen
und die entsprechenden Multilibs zu erzeugen ist ja keine große Aktion,
aber wer würde die limbm-Teil übernehmen mit sin, cos, tan, exp, log,
etc.?
Oder würde das bedeuten, daß der Distributor den Compiler zwingend mit
newlib verbandeln muß? Immerhin richtet die newlib die multilibs nach
gcc aus, nicht wie die avr-libc, wo das hart reingeklöppelt ist :-P
Johann L. schrieb:> Noch ne abschweifende Frage dazu: Im GCC double auf 64 Bits zu setzen> und die entsprechenden Multilibs zu erzeugen ist ja keine große Aktion,> aber wer würde die limbm-Teil übernehmen mit sin, cos, tan, exp, log,> etc.?
Genau das wäre die Frage. Es ist ja nicht nur sin, cos und Konsorten,
sondern dann müssten auch sinf, cosf usw. da sein (wofür man natürlich
die bisherigen Implementierungen benutzen kann).
Außerdem sollte das Ganze meiner Meinung nach noch zur Laufzeit
durch den Benutzer auswählbar sein, so ähnlich wie seinerzeit bei
-mint8, also ein -mdouble32 zum Beispiel. Die meisten Nutzer sind
ja mit der derzeitigen Implementierung durchaus zufrieden, sie gibt
einen relativ guten Gebrauchswert fürs Geld.
> Oder würde das bedeuten, daß der Distributor den Compiler zwingend mit> newlib verbandeln muß?
Wäre vermutlich beim derzeitigen Stand dann die einzige Variante. Das
passt ja zumindest dahingehend, dass das Gesamtergebnis ohnehin kaum
noch auf Controllern < 64 KiB sinnvoll zu benutzen sein wird. ;-)
Jörg Wunsch schrieb:> Johann L. schrieb:>>> Noch ne abschweifende Frage dazu: Im GCC double auf 64 Bits zu setzen>> und die entsprechenden Multilibs zu erzeugen ist ja keine große Aktion,>> aber wer würde die limbm-Teil übernehmen mit sin, cos, tan, exp, log,>> etc.?>> Genau das wäre die Frage. Es ist ja nicht nur sin, cos und Konsorten,> sondern dann müssten auch sinf, cosf usw. da sein (wofür man natürlich> die bisherigen Implementierungen benutzen kann).>> Außerdem sollte das Ganze meiner Meinung nach noch zur Laufzeit> durch den Benutzer auswählbar sein, so ähnlich wie seinerzeit bei> -mint8, also ein -mdouble32 zum Beispiel.
Gibt's doch bereits, nämlich -f[no-]short-double. Momentan ist implizit
-fshort-double gesetzt und die no-Version wird ignoriert. newlib
unterstützt übrigens -f[no-]short-double, d.h. mit der Option ist double
kurz, ein sin wird als sinf ausgeführt und printf passt sich auch an.
> Die meisten Nutzer sind ja mit der derzeitigen Implementierung> durchaus zufrieden, sie gibt einen relativ guten Gebrauchswert> fürs Geld.
Ja, die Sturm-und-Drang-Jahre der avr-Toolchain sind eindeutig vorbei...
>> Oder würde das bedeuten, daß der Distributor den Compiler zwingend mit>> newlib verbandeln muß?>> Wäre vermutlich beim derzeitigen Stand dann die einzige Variante. Das> passt ja zumindest dahingehend, dass das Gesamtergebnis ohnehin kaum> noch auf Controllern < 64 KiB sinnvoll zu benutzen sein wird. ;-)
M.E. nicht bei einer smarten Assemblerlösung nebst der Implementierung
des 64-Bit Move im avr-gcc.
Johann L. schrieb:> M.E. nicht bei einer smarten Assemblerlösung nebst der Implementierung> des 64-Bit Move im avr-gcc.
Schon richtig, aber dafür muss erstmal jemand Zeit und Muse haben.
(Mit anderen Worten: es muss jemand 64-bit-double so nötig brauchen
zusammen mit den übrigen avr-libc-Features, dass newlib für ihn keine
Option wäre und er stattdessen gewillt ist, den Aufwand in die
Erweiterung der avr-libc zu spendieren.)