Forum: PC-Programmierung Speicher reservieren mit malloc


von Jo (Gast)


Lesenswert?

Hallo,

ist diese Speicherreservieren so wie hier gezeigt mit malloc korrekt?

1
struct test
2
{
3
  objTest    *pTest;
4
  uint32_t   Var1;
5
  uint16_t   Var2;
6
};
7
8
test *ptr_test;
9
10
ptr_test = (test*)malloc(sizeof(test));

von Kaj (Gast)


Lesenswert?

Jo schrieb:
> so wie hier gezeigt mit malloc korrekt?
Du musst noch pruefen, ob du auch speicher bekommen hast.
1
ptr_test = (test*)malloc(sizeof(test));
2
3
if (ptr_test == NULL) {
4
    /* es konnte kein Speicher reserviert werden */
5
    /* was machst du, wenn du keinen Speicher    */
6
    /* bekommen hast?                            */
7
}
Ansonsten passt das.

Bei
1
ptr_test = (test*)malloc(sizeof(test));
scheiden sich die Geister, ob man den Rueckgabewert von malloc nun 
casten sollte oder nicht. In C++ musst du casten, in C kannst du casten, 
musst du aber nicht.

Beachte, dass bei malloc der Speicher nicht initialisiert wird!
Wenn du calloc benutzt, dann wird der Speicher mit 0 initialisiert.
http://www.cplusplus.com/reference/cstdlib/calloc/

von Jo (Gast)


Lesenswert?

Ok dann vielen Dank!

von Vlad T. (vlad_tepesch)


Lesenswert?

Jo schrieb:
> ist diese Speicherreservieren so wie hier gezeigt mit malloc korrekt?

ich würde folgendes bevorzugen:
1
ptr_test = malloc(sizeof(*ptr_test));

Grund:
wenn du den Pointertyp von "ptr_test" änderst, musst du bei meiner 
Variante das Malloc nicht anpassen - kannst es also auch nicht 
vergessen.

bezüglich:

Kaj schrieb:
> scheiden sich die Geister, ob man den Rueckgabewert von malloc nun
> casten sollte oder nicht. In C++ musst du casten, in C kannst du casten,
> musst du aber nicht.

in c++ könnte man aber auch direkt `new` benutzen - außer es kümmern 
sich C Funktionen um die Freigabe, dann ist die Ressourcenallokation 
allerdings asymetrisch und  das SW-Design doof.

: Bearbeitet durch User
von physiker (Gast)


Lesenswert?

Vlad T. schrieb:
>> scheiden sich die Geister, ob man den Rueckgabewert von malloc nun
>> casten sollte oder nicht. In C++ musst du casten, in C kannst du casten,
>> musst du aber nicht.
>
> in c++ könnte man aber auch direkt `new` benutzen - außer es kümmern
> sich C Funktionen um die Freigabe, dann ist die Ressourcenallokation
> allerdings asymetrisch und  das SW-Design doof.

Beim casten sollte man aber C++ style casts benutzen und raw pointer auf 
selbst reservierten space vermeiden (und kein delete).

von Rolf M. (rmagnus)


Lesenswert?

Kaj schrieb:
> Bei
> ptr_test = (test*)malloc(sizeof(test));
> scheiden sich die Geister, ob man den Rueckgabewert von malloc nun
> casten sollte oder nicht. In C++ musst du casten, in C kannst du casten,
> musst du aber nicht.

In C ist der Cast vollkommen unnötig.
Wenn man aber vergisst, den nötigen Header einzubinden, nimmt der 
Compielr an, dass malloc int zurückgibt. Ohne den Cast kommt dann eine 
Warnung. Mit Cast bleibt der Compiler ruhig, da du mit dem Cast sagst, 
dass du die Konvertierung so willst. Das ist der Grund, warum die 
meisten dazu raten, den Cast nicht hinzuschreiben - er kann einen Fehler 
verstecken.

Vlad T. schrieb:
> in c++ könnte man aber auch direkt `new` benutzen - außer es kümmern
> sich C Funktionen um die Freigabe, dann ist die Ressourcenallokation
> allerdings asymetrisch und  das SW-Design doof.

Das Design ist dann einfach kaputt und gehört repariert.

von Peter (Gast)


Lesenswert?

Später das free nicht vergessen!

von Sven B. (scummos)


Lesenswert?

Kaj schrieb:
> Jo schrieb:
>> so wie hier gezeigt mit malloc korrekt?
> Du musst noch pruefen, ob du auch speicher bekommen hast.
>
1
> ptr_test = (test*)malloc(sizeof(test));
2
> 
3
> if (ptr_test == NULL) {
4
>     /* es konnte kein Speicher reserviert werden */
5
>     /* was machst du, wenn du keinen Speicher    */
6
>     /* bekommen hast?                            */
7
> }
8
>

Wenn das nicht gerade irgendwas spezielles sicherheitskritisches ist, 
oder was was gigantische Matritzen auf einem Supercomputer 
multipliziert, ist das ziemlich sinnlos. Es macht den Code extrem schwer 
zu lesen, wenn nach jedem alloc ein if ( !x ) return ist, es ist sehr 
sehr schwer das insgesamt so hinzubekommen dass es sich sinnvoll verhält 
wenn der Speicher voll ist, und auf Systemen wie Linux kommt von malloc 
eh nie 0 zurück selbst wenn es keinen Speicher gibt. Dazu sind deine 
Optionen zur Fehlerbehandlung sehr beschränkt in den meisten Programmen, 
und ob du dann exit(0) machst oder einfach das null dereferenzierst ist 
ziemlich wurscht.

: Bearbeitet durch User
von Daniel A. (daniel-a)


Lesenswert?

Sven B. schrieb:
> und auf Systemen wie Linux kommt von malloc
> eh nie 0 zurück selbst wenn es keinen Speicher gibt.

Ich nutze linux und habe dass bereits gesehen. Dass passiert 
beispielsweise, wenn man versucht mehr Speicher zu reservieren als ram & 
swap verfügbar sind (es gibt jedoch die möglichkeit dieses verhalten 
auszuschalten). Wenn der Kernel speicher braucht, und es gibt keinen 
mehr, kommt dann der OOM-Killer und schiesst die speicherhungrigste 
Anwendung ab. Das kann z.B. passieren, wenn eine Page mit reserviertem 
Speicher zum ersten mal genutzt wird, wobei der Kernel erst zu dem 
Zeitpunkt versucht den speicher dafür tatsächlich zu reservieren.

Beitrag #4994061 wurde von einem Moderator gelöscht.
von Matthias K. (mkeller)


Lesenswert?

Sven B. schrieb:
> Wenn das nicht gerade irgendwas spezielles sicherheitskritisches ist,
> oder was was gigantische Matritzen auf einem Supercomputer
> multipliziert, ist das ziemlich sinnlos. Es macht den Code extrem schwer
> zu lesen, wenn nach jedem alloc ein if ( !x ) return ist, es ist sehr
> sehr schwer das insgesamt so hinzubekommen dass es sich sinnvoll verhält
> wenn der Speicher voll ist,


Sehe ich nicht so. Was ist an dem Code if(ptr == NULL) denn schwer 
verständlich? Es ist aus meiner Sicht gar keine Option den Fehler nicht 
abzufangen, denn sonst wird je nach OS das Programm irgendwann beim 
Zugriff beendet, wo es evt. sehr ungünstig ist.
Je nach Funktionalität die den Speicher brauch, muss man halt 
entsprechende Ersatzmaßnahmen einleiten. Evt. ist das malloc nur für ein 
optionales Feature gedacht und darf nicht gleich zum kill des ganzen 
Programms führen...

Gerade im Embedded-Bereich kann das böse enden!

von Sven B. (scummos)


Lesenswert?

Daniel A. schrieb:
> Ich nutze linux und habe dass bereits gesehen. Dass passiert
> beispielsweise, wenn man versucht mehr Speicher zu reservieren als ram &
> swap verfügbar sind (es gibt jedoch die möglichkeit dieses verhalten
> auszuschalten). Wenn der Kernel speicher braucht, und es gibt keinen
> mehr, kommt dann der OOM-Killer und schiesst die speicherhungrigste
> Anwendung ab. Das kann z.B. passieren, wenn eine Page mit reserviertem
> Speicher zum ersten mal genutzt wird, wobei der Kernel erst zu dem
> Zeitpunkt versucht den speicher dafür tatsächlich zu reservieren.

Ja, hast du im Detail natürlich recht, und man kann das overcommit auch 
per sysctl ausschalten. Aber wenn einfach nur der Speicher voll ist, 
kommt i.d.R. kein null zurück. Das typische "mein Programm reserviert zu 
viel Speicher weil Endlosschleife oder Leak"-Problem kriegst du damit 
nicht.


> Bloß weil du keine Ahnung hast, heißt es nicht, dass fehlertolerante
> Programmierung sinnlos wäre.
Es gibt viele Stellen, an denen defensive Programmierung hilfreich ist, 
aber nicht beim Speicher reservieren in der typischen 
Userspace-Anwendung. Das macht auch kein Mensch, weil es wie gesagt 
alles mit diesen Checks vollrümpelt und die Checks in den meisten 
Situationen sowieso nix machen können außer exit.
Ich habe mal hier bei $anwendung mit ~150k SLOC gegreppt, es gibt 2449 
memory allocations; wenn ich bei jeder ein if ( !x ) { return } dahinter 
baue, habe ich schon 7500 Zeilen Code produziert die das absolute 
Minimum sind, um sinnvoll zu reagieren, aber in der Form noch absolut 
gar nichts bringen. Im Gegenteil, die produzieren nur noch wirrere 
Fehlersituationen wenn eine davon tatsächlich auslöst.


> Sehe ich nicht so. Was ist an dem Code if(ptr == NULL) denn schwer
> verständlich?
Der Code ist verständlich, aber es wird wahnsinnig viel davon werden für 
sehr wenig Gewinn.

> Es ist aus meiner Sicht gar keine Option den Fehler nicht
> abzufangen, denn sonst wird je nach OS das Programm irgendwann beim
> Zugriff beendet, wo es evt. sehr ungünstig ist.
Pff, Pech, dann ist es halt weg. Viel mehr kannst du mit deinem Check 
auch nicht machen. :D


Meines Erachtens ist das wirklich an der völlig falschen Stelle auf 
irgendeine "Sauberkeit" auf dem Papier geachtet und als Tipp gerade für 
Anfänger sehr unpassend.  Die Software mit der man in der Praxis 
konfrontiert wird, stürzt ab, weil man in der "falschen" Reihenfolge auf 
zwei Buttons klickt. Da hätte man mal defensiv programmieren sollen, 
nicht bei der memory allocation.

von B. S. (bestucki)


Lesenswert?

Sven B. schrieb:
> Aber wenn einfach nur der Speicher voll ist,
> kommt i.d.R. kein null zurück. Das typische "mein Programm reserviert zu
> viel Speicher weil Endlosschleife oder Leak"-Problem kriegst du damit
> nicht.

Folgenden Code hat jedenfalls unter Linux meinen Speicher gefüllt, bis 
malloc NULL retournierte:
1
#include <stdlib.h>
2
#include <stdio.h>
3
4
int main(void){
5
  while(1){
6
    void * Ptr = malloc(1024);
7
    if(Ptr == NULL){
8
      printf("failed!\n");
9
      break;
10
    }
11
  }
12
  
13
  return 0;
14
}


Sven B. schrieb:
>> Es ist aus meiner Sicht gar keine Option den Fehler nicht
>> abzufangen, denn sonst wird je nach OS das Programm irgendwann beim
>> Zugriff beendet, wo es evt. sehr ungünstig ist.
> Pff, Pech, dann ist es halt weg. Viel mehr kannst du mit deinem Check
> auch nicht machen. :D

Meine Meinung: Lieber ein definiertes Verhalten mit exit, bei dem vorher 
evt. noch irgendwelche Daten gesichert werden können, als NULL zu 
dereferenzieren. Hängt halt immer von der Situation ab, welche Aktion 
die sinnvollste ist.

von Sven B. (scummos)


Lesenswert?

Be S. schrieb:
> Sven B. schrieb:
>> Aber wenn einfach nur der Speicher voll ist,
>> kommt i.d.R. kein null zurück. Das typische "mein Programm reserviert zu
>> viel Speicher weil Endlosschleife oder Leak"-Problem kriegst du damit
>> nicht.
>
> Folgenden Code hat jedenfalls unter Linux meinen Speicher gefüllt, bis
> malloc NULL retournierte:
Bei mir nicht.
1
» ./test
2
fish: “./test” terminated by signal SIGKILL (Forced quit)

von Jens G. (jensig)


Lesenswert?

SIGKILL -> OOM killer ...

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.