Forum: PC-Programmierung Strukturen mit memset initialisieren (C/C++)


von Thilo (Gast)


Lesenswert?

Hallo Leute,
bei uns in der Firma ist es "Konvention", Strukturen mit memset zu 
initialisieren. Also z.B.

struct myStruct
{
...
...
...
};

myStruct einsDavon;
memset( &einsDavon, (int)'\0', sizeof(myStruct) );

Dazu 2 Fragen:
1) Was soll der (int) Cast? warum nicht einfach:

memset( &einsDavon, 0, sizeof(myStruct) )

2) Es gibt Kollegen, die die ganze memset Initialisierung für Quatsch 
halten, für andere ist es unabdingbar.
Was spricht dagegen?

Als Berufsanfänger kann ich den Glaubenskrieg nicht richtig einordnen. 
Wäre dankbar für ein paar Meinungen dazu.

Gruß Thilo

von Peter II (Gast)


Lesenswert?

Thilo schrieb:
> Dazu 2 Fragen:
>
> 1) Was soll der (int) Cast? warum nicht einfach:
keine Ahnung - man braucht ihn zumindest nicht.

> memset( &einsDavon, 0, sizeof(myStruct) )
ja ist ok

> 2) Es gibt Kollegen, die die ganze memset Initialisierung für Quatsch
> halten, für andere ist es unabdingbar.

> Was spricht dagegen?
es spricht dagegen das es zeit und resourcen kostet, dafür spricht das 
man definierten werte am anfang hat.

von Thilo (Gast)


Lesenswert?

Peter II schrieb:
> ...

vielen Dank für die schnelle Antwort. Als Anfänger bin ich etwas 
unsicher gegenüber den "alten Hasenn". Deine Antwort bestärkt mich 
darin, es so zu machen, wie ich es "gelernt" habe und seit Jahren selbst 
praktiziere.

Gruß Thilo

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Möchte man so eine Struktur benutzen, ist es schon sinnvoll, wenn sie 
mit definierten Werten gefüllt ist. Eine Initialisierung ist also 
sinnvoll.

Allerdings ist eine explizite Initialisierung mit memset nicht immer 
nötig, je nachdem, woher der Speicher kommt, in dem die Struktur liegt.

Statische Variablen werden von der Laufzeitumgebung mit 0 initialisiert. 
Automatische Variablen (die auf dem Stack angelegt werden und nur für 
die Dauer der Gültigkeit des sie enthaltenen Blocks existieren) werden 
nicht von der Laufzeitumgebung initialisiert und enthalten daher mehr 
oder weniger zufällige Daten.

malloc liefert uninitialisierten Speicher, calloc initialisiert den 
Speicher mit 0.

Also ist der Gebrauch von memset bei Strukturen dann sinnvoll, wenn 
sie a) als automatische Variable auf dem Stack oder b) mit malloc 
angelegt werden.

> myStruct einsDavon;
> memset( &einsDavon, (int)'\0', sizeof(myStruct) );

Statt des Typecasts und der char-Konstante kann man hier vollkommen 
legal und mit exakt gleicher Auswirkung auch die int-Konstante 0 
verwenden.

von (unknown) (Gast)


Lesenswert?

Alle struct-
Variablen kann man aber auch mit ={0} initialisieren, das spart den 
Funktionsaufruf.
memset würde ich nur für Objekte nehmen, die mit malloc beschafft 
werden.
In C++ macht man
 das sowieso über einen Konstruktor.

Generell ist eine konsequente Initialisierung ein wichtiger Schritt weg 
vom Pfusch.

von Jasch (Gast)


Lesenswert?

Peter II schrieb:
> Thilo schrieb:
>> Dazu 2 Fragen:
[snip]
>> 2) Es gibt Kollegen, die die ganze memset Initialisierung für Quatsch
>> halten, für andere ist es unabdingbar.
>
>> Was spricht dagegen?
> es spricht dagegen das es zeit und resourcen kostet, dafür spricht das
> man definierten werte am anfang hat.

Wobei "definierte Werte" auch nur meistens hinhaut, Stichwort 
Portabilität.

Ein Pointer mit allen Bits 0 ist nicht notwendigerweise der Nullpointer, 
ein float oder double mit allen Bits 0 meines Wissens auch nicht 
notwendigerweise 0.0.

Hach, ein Struct mit 0-Bytes vollzupumpen könnte auch irgendwelche 
Padding-Bits auf eine Trap-Representation setzen.

Nachzulesen im C99-Standard.

von Thilo (Gast)


Lesenswert?

Jasch schrieb:
> Wobei "definierte Werte" auch nur meistens hinhaut, Stichwort
> Portabilität.
>
> Ein Pointer mit allen Bits 0 ist nicht notwendigerweise der Nullpointer,
> ein float oder double mit allen Bits 0 meines Wissens auch nicht
> notwendigerweise 0.0.
>
> Hach, ein Struct mit 0-Bytes vollzupumpen könnte auch irgendwelche
> Padding-Bits auf eine Trap-Representation setzen.
>
> Nachzulesen im C99-Standard.

Das ist natürlich prinzipiell richtig. Aber mal ehrlich: Im 
industriellen Bereich (also im wirklichen Leben von 99% aller 
Ingenieure) ist Portabilität kein Thema.

von !low level (Gast)


Lesenswert?

Schon mal so probiert?

myStruct einsDavon = {}

bzw. in C:

myStruct einsDavon = {0}

von Thilo (Gast)


Lesenswert?

!low level schrieb:
> Schon mal so probiert?

Ich wusste nicht, daß diese Syntax auf Strukturen anwenbar ist. Das ist 
natürlich die eleganteste Möglichkeit.

Vielen Dank für den Tipp!

von Rolf Magnus (Gast)


Lesenswert?

Rufus Τ. Firefly schrieb:
> Möchte man so eine Struktur benutzen, ist es schon sinnvoll, wenn sie
> mit definierten Werten gefüllt ist. Eine Initialisierung ist also
> sinnvoll.

Allerdings ist nicht generell für jedes Element jeder Struktur null ein 
sinnvoller Wert. Besser ist es daher, sie so weit wie möglich gleich 
richtig zu befüllen, statt sie erstmal blind mit Nullen zu füllen, die 
dann eh gleich wieder überschrieben werden.

> Also ist der Gebrauch von memset bei Strukturen dann sinnvoll, wenn
> sie a) als automatische Variable auf dem Stack oder b) mit malloc
> angelegt werden.

Bei automatischen Variablen würde aber auch eine explizite 
Initialisierung gehen.
1
myStruct einsDavon = { 0 };
alle folgenden Elemente werden dabei automatisch 0-initialisiert. Es 
wäre also höchstens bei malloc sinnvoll, und da kann ich dann auch 
gleich calloc stattdessen verwenden.

> Statt des Typecasts und der char-Konstante kann man hier vollkommen
> legal und mit exakt gleicher Auswirkung auch die int-Konstante 0
> verwenden.

'\0' ist eh schon nur in C++ eine char-Konstante. In C ist sie bereits 
vom Typ int. Aber so oder so kommt das selbe Ergebnis raus. Von der 
Code-Lesbarkeit her halte ich es aber für ziemlich unsinnig, '\0' zu 
verwenden, da das sugerriert, das Zielobjekt sei ein String.

von Jasch (Gast)


Lesenswert?

Thilo schrieb:
> Jasch schrieb:
>> Wobei "definierte Werte" auch nur meistens hinhaut, Stichwort
>> Portabilität.
>>
>> Ein Pointer mit allen Bits 0 ist nicht notwendigerweise der Nullpointer,
>> ein float oder double mit allen Bits 0 meines Wissens auch nicht
>> notwendigerweise 0.0.
>>
>> Hach, ein Struct mit 0-Bytes vollzupumpen könnte auch irgendwelche
>> Padding-Bits auf eine Trap-Representation setzen.
>>
>> Nachzulesen im C99-Standard.
>
> Das ist natürlich prinzipiell richtig. Aber mal ehrlich: Im
> industriellen Bereich (also im wirklichen Leben von 99% aller
> Ingenieure) ist Portabilität kein Thema.

Das ist schon richtig.

Ich fände es allerdings extrem beruhigend wenn dieses Thema zumindest 
allen Ingenieuren bekannt wäre - was es leider wohl nicht ist. Die Idee 
dass so ein PC-Fuzzi wegen Jobwechsels neuerdings die Steuerung des ABS 
in meinem Auto mit 99%-PC-Methoden programmiert (hat doch immer so 
funktioniert...) löst irgendwie Unbehagen aus...

von Vlad T. (vlad_tepesch)


Lesenswert?

Thilo schrieb:
> myStruct einsDavon;
> memset( &einsDavon, (int)'\0', sizeof(myStruct) );

schöner wäre auf jeden Fall:
1
myStruct einsDavon;
2
memset( &einsDavon, (int)'\0', sizeof(einsDavon) );
3
//                                    ^^^^^^^^^


bzw:
1
myStruct* einPointerDavon;
2
// ...
3
memset( einsDavon, (int)'\0', sizeof(*einPointerDavon) );
4
//                                    ^^^^^^^^^

der int cast ist in jedem Fall überflüssig

Btw:
in einem Sizeof darf man auch einen null-pointer oder einen ungültigen 
pointer dereferenzieren (schließlich ist es keine echte 
Dereffernzierung, da der Compiler das Sizeof zur Compilezeit berechnet).
zb:
1
myStruct* einPointerDavon;
2
einPointerDavon = (myStruct*) malloc(sizeof(*einPointerDavon));
3
memset( einsDavon, (int)'\0', sizeof(*einPointerDavon) );
4
//                                    ^^^^^^^^^

das verhindert bei Ändern des Types der Variable einPointerDavon, dass 
an x Stellen der Typ ersetzt werden muss und man das irgendwo vergisst

von Klaus W. (mfgkw)


Lesenswert?

Es gibt auch calloc().

von Reinhard Kern (Gast)


Lesenswert?

Jasch schrieb:
> Die Idee
> dass so ein PC-Fuzzi wegen Jobwechsels neuerdings die Steuerung des ABS
> in meinem Auto mit 99%-PC-Methoden programmiert (hat doch immer so
> funktioniert...) löst irgendwie Unbehagen aus...

Du brauchst halt ein entsprechend modernes Auto, dann erscheint auf dem 
zentralen Display die Meldung "bitte bremsen sie nicht, bis das 
ABS-System neu gebootet hat"...

Gruss Reinhard

von Thilo (Gast)


Lesenswert?

Jasch schrieb:
> Ich fände es allerdings extrem beruhigend wenn dieses Thema zumindest
> allen Ingenieuren bekannt wäre - was es leider wohl nicht ist. Die Idee
> dass so ein PC-Fuzzi wegen Jobwechsels neuerdings die Steuerung des ABS
> in meinem Auto mit 99%-PC-Methoden programmiert (hat doch immer so
> funktioniert...) löst irgendwie Unbehagen aus...

Ok, hab ich kapiert :-)

von Thilo (Gast)


Lesenswert?

Vlad Tepesch schrieb:
> schöner wäre auf jeden Fall:
> myStruct einsDavon;
> memset( &einsDavon, (int)'\0', sizeof(einsDavon) );
> //                                    ^^^^^^^^^
>
>
> bzw:myStruct* einPointerDavon;
> // ...
> memset( einsDavon, (int)'\0', sizeof(*einPointerDavon) );
> //                                    ^^^^^^^^^
>
> der int cast ist in jedem Fall überflüssig
>
> Btw:
> in einem Sizeof darf man auch einen null-pointer oder einen ungültigen
> pointer dereferenzieren (schließlich ist es keine echte
> Dereffernzierung, da der Compiler das Sizeof zur Compilezeit berechnet).
> zb:myStruct* einPointerDavon;
> einPointerDavon = (myStruct*) malloc(sizeof(*einPointerDavon));
> memset( einsDavon, (int)'\0', sizeof(*einPointerDavon) );
> //                                    ^^^^^^^^^
>
> das verhindert bei Ändern des Types der Variable einPointerDavon, dass
> an x Stellen der Typ ersetzt werden muss und man das irgendwo vergisst

Guter Punkt, vielen Dank!

von Karl (Gast)


Lesenswert?

Jasch schrieb:
> Wobei "definierte Werte" auch nur meistens hinhaut, Stichwort
> Portabilität.
>
> Ein Pointer mit allen Bits 0 ist nicht notwendigerweise der Nullpointer,
> ein float oder double mit allen Bits 0 meines Wissens auch nicht
> notwendigerweise 0.0.
>
> Hach, ein Struct mit 0-Bytes vollzupumpen könnte auch irgendwelche
> Padding-Bits auf eine Trap-Representation setzen.
>
> Nachzulesen im C99-Standard.

Das interessiert mich jetzt näher. Ich habe ein bischen dazu 
recherchiert. Meistens fand ich was zu Zahlen in anderer Darstellung, 
also 1er/2er-Komplement etc. Natürlich kann Float auch anders definiert 
sein als IEEE754.

Soweit so gut. Somit wäre das Problem, das RAM der Daten wird mit Bits 
gefüllt, beim Zugriff auf das RAM mit Interpretation des Datentyps 
(Float bspw.) gibt es dann ein Problem.

Du sprichst allerdings auch padding bei Strukturen an. Das wäre dann 
allerdings ein anderes Problem, richtig? Allerding erfolgt später kein 
Zugriff auf diese Padding-Bits, weil sonst wären das ja Daten.

Und zur praktischen Veranschaulichung, kennst du eine Plattform bei der 
sowas tatsächlich auftritt?

Vielen Dank für diesen Punkt, man lernt immer dazu!

von schmitti (Gast)


Lesenswert?

BTW,
die Initialisierung in "C" mit
mystruct s = {0};
funktioniert nur wenn dem ersten Element der Struktur auch ein integer 0 
zugewiesen werden kann.
In "C++" geht es jedoch mit s = {} immer.

von Rolf Magnus (Gast)


Lesenswert?

schmitti schrieb:
> BTW,
> die Initialisierung in "C" mit
> mystruct s = {0};
> funktioniert nur wenn dem ersten Element der Struktur auch ein integer 0
> zugewiesen werden kann.

In C gilt das für jeden skalaren Datentyp. Für die anderen wird dann 
noch ein weiteres Klammernpaar fällig.

von Jasch (Gast)


Lesenswert?

Karl schrieb:
> Jasch schrieb:
>> Wobei "definierte Werte" auch nur meistens hinhaut, Stichwort
>> Portabilität.
>>
>> Ein Pointer mit allen Bits 0 ist nicht notwendigerweise der Nullpointer,
>> ein float oder double mit allen Bits 0 meines Wissens auch nicht
>> notwendigerweise 0.0.
>>
>> Hach, ein Struct mit 0-Bytes vollzupumpen könnte auch irgendwelche
>> Padding-Bits auf eine Trap-Representation setzen.
>>
>> Nachzulesen im C99-Standard.
>
> Das interessiert mich jetzt näher. Ich habe ein bischen dazu
> recherchiert. Meistens fand ich was zu Zahlen in anderer Darstellung,
> also 1er/2er-Komplement etc. Natürlich kann Float auch anders definiert
> sein als IEEE754.

Naja, das ist ja schon fast alles was so ein Computer verarbeiten kann, 
alles weitere (Zeichen, Pixel, ...) ist dann ja nur noch 
Interpretationssache.

> Soweit so gut. Somit wäre das Problem, das RAM der Daten wird mit Bits
> gefüllt, beim Zugriff auf das RAM mit Interpretation des Datentyps
> (Float bspw.) gibt es dann ein Problem.

Oder auch beim Verschicken übers Netzwerk u.ä., da ist der ganz 
offensichtliche Fall unterschiedliche Endianness (siehe ntohs(), ntohl() 
usw.).

> Du sprichst allerdings auch padding bei Strukturen an. Das wäre dann
> allerdings ein anderes Problem, richtig? Allerding erfolgt später kein

Richtig.

> Zugriff auf diese Padding-Bits, weil sonst wären das ja Daten.

Durch das C-Programm nicht, durch die Hardware vielleicht schon. Stell 
Dir z.B. RAM mit 8 Bits/Byte plus einem Parity-Bit vor, wobei sowas fuer 
C normalerweise transparent wäre.

> Und zur praktischen Veranschaulichung, kennst du eine Plattform bei der
> sowas tatsächlich auftritt?

Nein, Gott sei dank! Sowas ist meines Wissens eher unüblich, jedenfalls 
innerhalb der heutigen Mainstream-Hardware.

Das Parity-Problem hat mich vor vielen Jahren mal in den Hintern 
gebissen, da habe ich vom BIOS nicht eingeschalteten RAM (oberhalb 640K, 
ja das war noch unter DOS ;-) eingeschaltet. Die Hardware hatte Parity 
fürs RAM, ziemlich jeder Lesezugriff auf den "neuen" Speicher ging 
schief bis ich den erstmal mit Nullen vollgeschrieben habe um die 
Parity-Bits zu initialisieren.

Hmm, ich denke mir mal ein Szenario aus: eine Hardware mit 
32-Bit-Speicherbus, mit einem 24-Bit-Integer-Typen - manche DSPs haben 
so einen - mit Alignment 4 Byte, der Hardware-Designer war voll auf 
Drogen und deshalb will die Hardware die obersten 4 Bits als 0xf sehen - 
sonst gibt es einen Zugriffsfehler. Ein Füllen eines structs mit Nullen 
wird hier nicht funktionieren wenn es einen dieser 24-Bit-Integer 
enthält.

Würde jemand solche Hardware designen? Hmm, unmöglich ist nix, die 
Hardware-Entwickler nehmen manchmal erstaunlich wenig Rücksicht auf die 
SW-Entwickler die mit dem Zeug dann was machen sollen.

von schmitti (Gast)


Lesenswert?

Rolf Magnus schrieb:
> schmitti schrieb:
>> BTW,
>> die Initialisierung in "C" mit
>> mystruct s = {0};
>> funktioniert nur wenn dem ersten Element der Struktur auch ein integer 0
>> zugewiesen werden kann.
>
> In C gilt das für jeden skalaren Datentyp. Für die anderen wird dann
> noch ein weiteres Klammernpaar fällig.

AFAIK wird der Compiler bei einem enum aber meckern, dass der Typ nicht 
kompatibel ist, und ein Cast wäre irgendwie Pfusch.

von Andreas B. (andreas_b77)


Lesenswert?

Ganz abgesehen von der Korrektheit des Programms ist Initialisierung mit 
Nullen auch wichtig für Datenstrukturen, die irgendwann in einer Datei 
enden oder übers Netzwerk gesendet werden. Wenn man nur die Felder 
einzeln initialisiert, bleiben Padding, nicht voll ausgenutzte 
String-Elemente (v.a. bei Initialisierung mit einem leeren String) und 
sonstige Arrays, in der nur genutzte Felder initialisiert werden, 
unangetastet.

Soll heißen sie enthalten irgendwelche Daten, die vorher im Speicher an 
der Stelle standen. Das kann alles von belanglos bis extrem sensibel 
sein. Ein Grund warum man Datenfelder die Passwörter o.ä. enthalten auch 
vor dem Freigeben noch mal überschreiben sollte.

von Jasch (Gast)


Lesenswert?

Andreas B. schrieb:
> Ganz abgesehen von der Korrektheit des Programms ist Initialisierung mit
> Nullen auch wichtig für Datenstrukturen, die irgendwann in einer Datei
> enden oder übers Netzwerk gesendet werden. Wenn man nur die Felder
> einzeln initialisiert, bleiben Padding, nicht voll ausgenutzte
> String-Elemente (v.a. bei Initialisierung mit einem leeren String) und
> sonstige Arrays, in der nur genutzte Felder initialisiert werden,
> unangetastet.

Uhh, ohh, aber sowas zu machen ist von vornherein ein Designdesaster.

Die In-Memory-Datenstrukturen und die übers Netzwerk verschickten oder 
auf die Platte geschriebenen Daten haben strukturell genau garnichts 
miteinander zu tun.

Nur weil ich im Speicher einen 32-Bit-Int habe heisst noch nicht dass 
das im Netz nicht ein 16-Bit-Int sein kann, mit anderer Endianness, oder 
der Null-terminierte String im Speicher könnte im Netz einer im 
Pascal-Format sein, mit einem anderen Encoding obendrein.

Jeder Versuch die Speicherdatenstrukturen sklavisch zur externen 
Datenrepräsentation identisch zu machen endet potentiell in der 
Katastrophe.

von Andreas B. (andreas_b77)


Lesenswert?

Jasch schrieb:
> Die In-Memory-Datenstrukturen und die übers Netzwerk verschickten oder
> auf die Platte geschriebenen Daten haben strukturell genau garnichts
> miteinander zu tun.

Na, irgendwo wirst du irgendwann mal einen Puffer zusammenstellen 
müssen, der die Daten zum Senden/Schreiben enthält. Denn alle solchen 
Transfers geschehen aus dem Speicher. Außer auf kleinen Mikrocontrollern 
ohne DMA, aber dort wird man meist eh auf Library-Routinen 
zurückgreifen, die am Ende auch wieder eine Adresse und Länge erwarten.

von Jasch (Gast)


Lesenswert?

Andreas B. schrieb:
> Jasch schrieb:
>> Die In-Memory-Datenstrukturen und die übers Netzwerk verschickten oder
>> auf die Platte geschriebenen Daten haben strukturell genau garnichts
>> miteinander zu tun.
>
> Na, irgendwo wirst du irgendwann mal einen Puffer zusammenstellen
> müssen, der die Daten zum Senden/Schreiben enthält. Denn alle solchen
> Transfers geschehen aus dem Speicher. Außer auf kleinen Mikrocontrollern
> ohne DMA, aber dort wird man meist eh auf Library-Routinen
> zurückgreifen, die am Ende auch wieder eine Adresse und Länge erwarten.

Dem stimme ich zu. ;-)

Es las sich halt für mich als ob Du irgendwelche Structs direkt ins 
Netzwerk pusten wolltest.

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.