Forum: PC-Programmierung Automatische Initialisierung von Variablen & Co.


von Dennis S. (eltio)


Lesenswert?

Guten Morgen zusammen!

In C haben die angelegten Variablen ja bekanntlich einen zufälligen 
Inhalt wenn Sie nicht initialisiert werden. Für Arrays gilt das gleiche. 
Wie sieht es mit Strukturen aus?

Ich habe ein paar Versuche nach folgendem Prinzip gemacht
1
typedef struct {
2
    int16_t skalar;
3
    int16_t vektor[15];
4
}struktur_t;
5
struktur_t mein_array;

Anscheinend haben alle Elemente auf die ich zugreifen kann den Wert 0. 
Kann das jemand bestätigen oder ist das "Zufall"?

Eine weitere Frage: wie kann ich möglichst einfach ein zweidimensionales 
Array mit Null füllen? Spricht etwas dagegen:
1
int array[n][m];
2
memset(array, 0, sizeof(int) * n * m);

Letzte Frage: Ist es richtig, dass ich mich nicht darauf verlassen kann, 
dass oben genannte Struktur fein säuberlich hintereinander im Speicher 
liegt? Eine Null-Initialisierung nach obigem Beispiel würde also 
rausfallen. Gibt es da eine einfache Alternative?

Gruß Dennis

von Peter II (Gast)


Lesenswert?

Dennis S. schrieb:
> In C haben die angelegten Variablen ja bekanntlich einen zufälligen
> Inhalt wenn Sie nicht initialisiert werden.

nein, alle globalen und static Variablen werden mit initialisiert.

> Letzte Frage: Ist es richtig, dass ich mich nicht darauf verlassen kann,
> dass oben genannte Struktur fein säuberlich hintereinander im Speicher
> liegt?
wie soll das gehen, wie sie nicht hintereinander im Speicher liegt, dann 
könnte man ja auch nicht darauf zugreifen?

> Eine Null-Initialisierung nach obigem Beispiel würde also
> rausfallen.
nein, genauso kann man es machen.

> Gibt es da eine einfache Alternative?
braucht man ja nicht.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Peter II schrieb:
>> Letzte Frage: Ist es richtig, dass ich mich nicht darauf verlassen kann,
>> dass oben genannte Struktur fein säuberlich hintereinander im Speicher
>> liegt?
> wie soll das gehen, wie sie nicht hintereinander im Speicher liegt, dann
> könnte man ja auch nicht darauf zugreifen?

Das Stichwort lautet hier Alignment. Aus Optimierungs- und 
Architekturgründen kann sehr wohl zwischen den einzelnen 
Strukturelementen etwas Platz gelassen werden, damit mit an von der 
Prozessorarchitektur bevorzugten Adressgrenzen ausgerichteten Zugriffen 
gearbeitet werden kann.

Nehmen wir mal ein 32-Bit-System und folgende Struktur an:
1
struct bla
2
{
3
  uint8_t wert1;
4
  uint32_t wert2;
5
}

Wird die Struktur selbst an einer für 32-Bit-Zugriffen geeigneten 
Adresse (also einer restlos durch 4 teilbaren) ausgerichtet, läge das 
Strukturelement wert2 um eins "daneben".
Etliche 32-Bit-Systeme können hier keinen 32-Bit-Zugriff ausführen, 
sondern müssen aufwendig mit Einzelbyte-Zugriffen arbeiten, so daß die 
Performance hier massiv leidet.

Deswegen werden hier drei Füllbytes eingeschoben, so daß ein sizeof 
der Struktur den Wert 8 und nicht, wie erwartet, 5 zurückgibt.

Mit compilerspezifischen Anweisungen à la #pragma pack oder _packed_ 
(näheres siehe des Compilers Dokumentation) lässt sich die "langsame" 
Variante erzwingen.

von Dennis S. (eltio)


Lesenswert?

Peter II schrieb:
> Dennis S. schrieb:
>> In C haben die angelegten Variablen ja bekanntlich einen zufälligen
>> Inhalt wenn Sie nicht initialisiert werden.
>
> nein, alle globalen und static Variablen werden mit initialisiert.
Ach, daran habe ich nicht gedacht! Es handelt sich bei meiner Struktur 
tatsächlich um eine Globale.

>> Letzte Frage: Ist es richtig, dass ich mich nicht darauf verlassen kann,
>> dass oben genannte Struktur fein säuberlich hintereinander im Speicher
>> liegt?
> wie soll das gehen, wie sie nicht hintereinander im Speicher liegt, dann
> könnte man ja auch nicht darauf zugreifen
Aus diesem Thread lese ich das irgendwie anders:
Beitrag "Aufbau von Structs im Speicher"

>> Gibt es da eine einfache Alternative?
> braucht man ja nicht.
Doch, FALLS einzelnen Elemente der Struktur nicht hintereinander im 
Speicher liegen. Ansonsten:
1
struktur_t mein_array;
2
memset(&mein_array, 0, sizeof(struktur_t));

Vielleicht kann jemand noch mal erläutern wo der Unterschied zwischen 
meiner Struktur (die kann auch anders aussehen!) und dem verlinkten 
Thread ist?

Gruß Dennis

von Peter II (Gast)


Lesenswert?

Rufus Τ. Firefly schrieb:
> Das Stichwort lautet hier Alignment.

das spielt über für das nullen keine Rolle. Wenn die füllbytes da sind 
werden sie auch mit 0 gefüllt.

von Dennis S. (eltio)


Lesenswert?

Danke Rufus, das habe ich vorhin auch gefunden! Und bestätigt mich ja 
auch ein wenig in meinen "Befürchtungen".. Also was bleibt mir? Alle 
Elemente einzeln "Nullen"?

Gruß Dennis

von Dennis S. (eltio)


Lesenswert?

Peter II schrieb:
> Rufus Τ. Firefly schrieb:
>> Das Stichwort lautet hier Alignment.
>
> das spielt über für das nullen keine Rolle. Wenn die füllbytes da sind
> werden sie auch mit 0 gefüllt.

Kann es nicht sein, dass in den Füllbytes "fremde" Daten liegen?

von Peter II (Gast)


Lesenswert?

Dennis S. schrieb:
> Danke Rufus, das habe ich vorhin auch gefunden! Und bestätigt mich ja
> auch ein wenig in meinen "Befürchtungen".. Also was bleibt mir? Alle
> Elemente einzeln "Nullen"?

nein, brauchst du nicht. Selbst wenn Lücken vorhanden sind, werden sie 
ja bei sizeof mit berücksichtig.

von Peter II (Gast)


Lesenswert?

Dennis S. schrieb:
> Kann es nicht sein, dass in den Füllbytes "fremde" Daten liegen?

nein, auf keinen Fall

von Dennis S. (eltio)


Lesenswert?

Okay, vielen Dank.. wieder was gelernt! :-)

von Volle (Gast)


Lesenswert?

Alligment Lücken sind  verschwendeter Platz
zur Reduzierung Variablen, auch in Strukturen, möglichst von Großen Typ 
zum kleinen Typ sortieren.

Laut Standard werden übrigens nicht initialisierte Variablen beim Start 
vom System auf 0 gesetzt.
Wer selbst ein Standard konformes System bauen will, muss das bei einem 
Reset auch selbst so implementieren.

von Dennis S. (eltio)


Lesenswert?

Volle schrieb:
> zur Reduzierung Variablen, auch in Strukturen, möglichst von Großen Typ
> zum kleinen Typ sortieren.
Kannst du dafür ein Beispiel geben?

von Konrad S. (maybee)


Lesenswert?

Volle schrieb:
> Laut Standard werden übrigens nicht initialisierte Variablen beim Start
> vom System auf 0 gesetzt.

... sofern es Variablen sind, die der Initialisierung unterliegen, also 
globale und statische.

von Volle (Gast)


Lesenswert?

ganz einfach rechne mal für beide Beispiele die Lücken aus wenn der 
Prozessor ( wie viele) bei 32Bit Variable nur auf durch 4 teilbare 
Adressen
und bei 16 Bit Variablen auf gerade Adresse zugreifen kann


gutes Beispiel:

uint32_t a;
uint32_t b;
uint16_t c;
uint16_t d;
uint8_t  e;
uint8_t  f;
uint8_t  g;
uint8_t  h;

schlechtes Beispiel

uint8_t  f;
uint32_t a;
uint8_t  e;
uint16_t c;
uint8_t  h;
uint32_t b;
uint8_t  g;
uint16_t d;



Strukturen haben bei 32Bit Prozessoren meist auch eine durch 4 teilbare 
Startadresse.
Das legt die EABI in der Regel so fest und die Compiler sollten sich 
dran halten.

von Fabian O. (xfr)


Lesenswert?

Dennis S. schrieb:
> Eine weitere Frage: wie kann ich möglichst einfach ein zweidimensionales
> Array mit Null füllen? Spricht etwas dagegen:
> int array[n][m];
> memset(array, 0, sizeof(int)  n  m);
1
int array[n][m] = {0};
Das gilt auch für Strukturen. Sobald Du in der Initialisierungsliste 
mindestens einem Element einen Wert gibst, werden alle anderen "nicht 
genannten" Elemente mit 0 initialisiert.

von Volle (Gast)


Lesenswert?

Konrad S. schrieb:
> Volle schrieb:
>> Laut Standard werden übrigens nicht initialisierte Variablen beim Start
>> vom System auf 0 gesetzt.
>
> ... sofern es Variablen sind, die der Initialisierung unterliegen, also
> globale und statische.


ja,
aber bei lokalen nicht static prüft der Compiler ob zuerst gelesen oder 
geschrieben wird und schimpft falls es falsch ist.
Bei globalen kann es das nicht.

von Peter II (Gast)


Lesenswert?

Volle schrieb:
> aber bei lokalen nicht static prüft der Compiler ob zuerst gelesen oder
> geschrieben wird und schimpft falls es falsch ist.

daruf kann man sich aber nicht verlassen!
1
void foo() {
2
   int i;
3
   bar(&i);
4
   printf("%d", i );
5
}

hier wird kein Compiler schimpfen, weil er nicht weiss ob i in bar 
geschrieben wird oder nicht.

von Volle (Gast)


Lesenswert?

Bei Funktionsaufrufen enden die Überprüfungen (und auch die 
Optimierungen)

Ich habe mal ein Tool geschrieben das die Zugriffe auf Variablen und 
Konstanten auf Obj-Code Ebene für eine Gesamtsoftware analysiert.
bei ca 95% Vollständigkeit hab ich aufgehört.
Da ging es aber darum Elemente zu finden die nicht gelesen werde
und überflüssig sind.

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.