C structs Ausnullen

Seit Ewigkeiten nutze ich
struct structtype instance = {0};
um Strukturen am Stack “generisch” mit Nullen zu initialisieren.

Doch … effizient ist das nicht, wenn man auf den generierten Code schaut.


Watcom’s DOS EXEn

Dass Programme “zu groß” sind fällt mir immer nur in der DOS Welt auf. Schließlich hat keiner mehr einen Überblick, ob die Windows CRT oder Linux GLIBC jetzt 100 oder 200 KB einfach nur so zum Spaß anhängen. Man akzeptiert den digitalen Müll einfach.

Aber wenn das Programm zum Auflisten eines Verzeichnisses plötzlich 50 KByte groß wird, und man weiß, dass es funktional nur wenige KB sein dürften, dann wird man wach.

Das tolle ist, dass Watcom beim Kompilieren immer sein .map Dateien anlegt, wo jede Funktion und jeder Datenblock mit Adresse und Größe in einer lesbaren Tabelle landet.
Und dort sind mir dann einige Blöcke aufgefallen, die mehrere Kilobytes groß waren.

Kopier-Schatten bei der Initialisierung

Wenn ich am Anfang einer C-Funktion die Variablen deklariere, werden die meistens ausgenullt. Bei structs führt ein = { 0 } dazu, dass alle Felder (und nicht nur das erste) ausgenullt werden.

Als ich spaßhalber mal eine der Initialisierungen entfernt hatte, sank sofort die Größe der EXE und auch die Ausdehnung des Datenbereiches in der .map Tabelle.

Offenbar erzeugt der Compiler einen statisch mit Nullen ausgefülltes Feld im Datenbereich und kopiert dieses bei der Initialisierung über die Variable auf dem Stack.
Das fällt natürlich bei Kleinkram niemandem auf, doch ich erzeuge ja gerne Puffer-Strukturen, die dann Member mit mehrere Kilobytes haben.
Wenn diese structs also bei jeder Initialisierung zu einer versteckten Leerkopie im Datensegment führen, bläht sich mein Programm unnötig auf.

Lösung: memset

Ich ging also durch meine Initialiserungszeilen durch und ersetzte diese beiden größeren Objekten durch ein:

1//struct mytype struct_var = {0};
2struct mytype struct_var;
3memset(&struct_var, 0, sizeof(struct_var));

Resultat: Meine DOS EXEen sind wieder um 20 KByte kleiner geworden.
Der größte Zuwachs kam durch meine Koroutinenen-Implementierung ins Framework, denn diese wird in DOS jetzt zwingend am Start initialisiert und dort wurde für mehrere potentielle Stacks Verwaltungsbereich vorinitialisiert.

Fazit

Tja … es kann gut sein, dass andere Compiler hier besser optimieren und es gar nicht zu solchen Init-Kopien kommt. Aber nachdem man es nicht ausschließen kann, gilt für mich ab sofort die Regel:

structs größer als 32 Bytes dürfen nicht mehr per { 0 } initialisiert werden.

Und wieder einmal belehrt mich ein Altsystem, dass ich fahrlässig mit Ressourcen umgegangen bin. Und so lernt man aus der Vergangenheit, wie man mit einer Zeile eine bessere Zukunft “aufbauen” kann.

📧 📋 🐘 | 🔔
 

Meine Dokus über:
 
Weitere externe Links zu:
Alle extern verlinkten Webseiten stehen nicht in Zusammenhang mit opengate.at.
Für deren Inhalt wird keine Haftung übernommen.



Wenn sich eine triviale Erkenntnis mit Dummheit in der Interpretation paart, dann gibt es in der Regel Kollateralschäden in der Anwendung.
frei zitiert nach A. Van der Bellen
... also dann paaren wir mal eine komplexe Erkenntnis mit Klugheit in der Interpretation!