Forum: Compiler & IDEs kurze frage zur Init.


von öhm (Gast)


Lesenswert?

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

: Verschoben durch User
von Peter II (Gast)


Lesenswert?

ö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.

von Ralf G. (ralg)


Lesenswert?

öhm schrieb:
> Soweit ich weiß, steht da am Anfang sowieso
> überall 0 drin.

Ist nicht garantiert! Wird aber oft|meistens vom Compiler so gemacht.

von Kaj (Gast)


Lesenswert?

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

von öhm (Gast)


Lesenswert?

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.

von öhm (Gast)


Lesenswert?

Hallo Kaj.

Danke für die Antwort! Genau so ne Aussage hab ich gesucht. :)
Mein Bauchgefühl hat mir nämlich das gleiche gesagt.


gruß
öhm

von Kaj (Gast)


Lesenswert?

Gerne doch. =)

von Stefan E. (sternst)


Lesenswert?

ö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.

von Karl H. (kbuchegg)


Lesenswert?

ö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.

von öhm (Gast)


Lesenswert?

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

von Peter II (Gast)


Lesenswert?

ö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.

von Steel (Gast)


Lesenswert?

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;

von Peter II (Gast)


Lesenswert?

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.

von öhm (Gast)


Lesenswert?

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.

von Stefan E. (sternst)


Lesenswert?

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.

von Nachbar (Gast)


Lesenswert?

ö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.

von Peter II (Gast)


Lesenswert?

ö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.

von Stefan E. (sternst)


Lesenswert?

ö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".

von öhm (Gast)


Lesenswert?

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?

von Kaj (Gast)


Lesenswert?

ö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

von Stefan E. (sternst)


Lesenswert?

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.

von öhm (Gast)


Lesenswert?

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?

von Steel (Gast)


Lesenswert?

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.

von Peter II (Gast)


Lesenswert?

öhm schrieb:
> 1.h:
> struct test
> {
> }test;
>
> 2.h:
>
> extern test;
>
> Oder wie?

so müsste es richtig sein:

1.h:
struct testS
{
};

extern struct testS test;

1.c:
struct testS test;

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Beim avr-gcc muss man etwas aufpassen mit der Initialisierung von Daten 
im static storage:

Siehe PR18145 und die Anmerkung dazu in den 4.7 Release Notes:

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=18145
http://gcc.gnu.org/gcc-4.7/changes.html

PR18145 war teilweise auch schon vor 4.7 implementiert, etwa in 
WinAVR-20100110 (avr-gcc 4.3.3).

von Karl H. (kbuchegg)


Lesenswert?

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

von öhm (Gast)


Lesenswert?

Ach mann ist das ein mist...


Folgendes hab ich nun abgeändert, funktioniert so aber nicht:
1
1.h:
2
3
struct testS
4
{
5
  int dummy;
6
7
};
8
extern struct testS test;
1
1.c:
2
struct testS test = {0};
1
main.c:
2
#include "1.h"
3
4
int main(void)
5
{
6
   dummy = 3;
7
}


Was ist da schon wieder falsch?

von Karl H. (kbuchegg)


Lesenswert?

öhm schrieb:

>
1
> main.c:
2
> #include "1.h"
3
> 
4
> int main(void)
5
> {
6
>    dummy = 3;
7
> }
8
>
>
>
> Was ist da schon wieder falsch?

du meintest
1
   test.dummy = 3;

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.

von öhm (Gast)


Lesenswert?

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
void Init()
3
{
4
  struct testS test = {0};
5
}
6
7
anstatt:
8
9
1.c:
10
11
struct testS test = {0};
12
13
void Init()
14
{
15
}


Wobei dann die Frage ensteht ob ich das void init überhaupt noch 
brauche.

von öhm (Gast)


Lesenswert?

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?

von Peter II (Gast)


Lesenswert?

öhm schrieb:
> 1.c:
> void Init()
> {
>   struct testS test = {0};
> }

hier legst du eine funktionslokale Variabel an und verwendest nicht die 
globale.

von Karl H. (kbuchegg)


Lesenswert?

ö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
typedef struct testS myTestS;

Jetzt hast du einen neuen Datentyp vereinbart, den du in weiterer Folge 
benutzen kannst. Zb um damit Variablen zu definieren oder deklarieren 
...
1
myTestS test;

... 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.

von öhm (Gast)


Lesenswert?

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;
}

von Karl H. (kbuchegg)


Lesenswert?

öhm schrieb:

> Ich möchte ja das globale struct initialisieren. Denke es müsste so
> sein:
.... initialisieren .....

>
1
> 1.c:
2
> 
3
> struct testS test;
4
> 
5
> void Init ()
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
  const int i = 5;      // ist ok. Das ist eine Initialisierung
2
3
  const int j;
4
  j = 8;                // ist nicht ok. Das ist eine Zuweisung

von öhm (Gast)


Lesenswert?

Verstehe.
@Karl Heinz Buchegger:  Danke :)


Welchen Vorteil hat dieser Code:
1
struct testS test = {0};
2
3
int main ()
4
{
5
...
6
}

vor diesem:
1
struct testS test;
2
3
4
void Init (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....

von Peter II (Gast)


Lesenswert?

ö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.

von öhm (Gast)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

ö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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

ö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.

von Andreas B. (andreas_b77)


Lesenswert?

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.

von öhm (Gast)


Lesenswert?

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?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

ö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.

von öhm (Gast)


Lesenswert?

Stimmt auch wieder.


Ich danke allen vielmals für das angenehme Gespräch! Ich habe was dazu 
gelernt. :)  Tolles Forum.


gruß
öhm

von öhm (Gast)


Lesenswert?

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

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

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.

von B. S. (bestucki)


Lesenswert?

ö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.

von öhm (Gast)


Lesenswert?

Ah, ich sehe grad im Datenblatt, dass unter jedem Register die "initial 
values" eingetragen sind. Danke!

Wie war das nochmals:

   X  =   undefined
  N/A =  ?

von Karl H. (kbuchegg)


Lesenswert?

ö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.

von W.S. (Gast)


Lesenswert?

ö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.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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?

von B. S. (bestucki)


Lesenswert?

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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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?
;-)

von B. S. (bestucki)


Lesenswert?

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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

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

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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. ;-)

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.)

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.