kurze frage zur Init.

Gast #3215709
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.
Gast #3215725
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
Gast #3215727
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.
#3215736
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.
Gast #3215752
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
Gast #3215756
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.
Gast #3215764
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.
Gast #3215765
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.
Gast #3215771
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.
Gast #3215774
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.
#3215786
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".
#3215844
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
Gast #3215847
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?
#3215853
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.
Gast #3215878
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.
#3215991
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.
Gast #3216002
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;
}
#3216016
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
Gast #3216044
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....
Gast #3216050
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.
Gast #3216070
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.
#3216107
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.
Moderator Persönliche Seite #3216108
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.
#3216153
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.
Gast #3216338
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?
Moderator Persönliche Seite #3216357
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.
Gast #3226674
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
#3226685
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.
#3226744
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.
Gast #3226753
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.
Persönliche Seite #3226764
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.
#3226817
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?
#3226934
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.
Moderator Persönliche Seite #3226962
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?
;-)
#3226977
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.
Moderator Persönliche Seite #3226985
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.
Persönliche Seite #3226989
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
Moderator Persönliche Seite #3227033
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. ;-)
Persönliche Seite #3227045
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.
Moderator Persönliche Seite #3227071
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.)

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