"Komfort" bei malloc
-
namespace invader schrieb:
allein um malloc-Fehlschläge abzufangen, die in der Praxis vermutlich ohnehin niemals auftreten.
Das kommt halt auf das Programm an. Bei uns gibt es solche Fälle (wir hantieren aber auch mit sehr großen Speicherblöcken). Das kleine Prgrämmchen, das in Summe 20 MB braucht, wird malloc-Fehler wohl kaum zu Gesicht bekommen.
-
namespace invader schrieb:
Besser ist stattdessen
if (!m && length)
, da malloc ja NULL zurückgeben kann, wenn man ein Array der Länge 0 haben will.Was man auch als Fehler ansehen könnte.
-
_matze schrieb:
Das kommt halt auf das Programm an. Bei uns gibt es solche Fälle (wir hantieren aber auch mit sehr großen Speicherblöcken). Das kleine Prgrämmchen, das in Summe 20 MB braucht, wird malloc-Fehler wohl kaum zu Gesicht bekommen.
Ok, kommt eben darauf an: Wenn man sehr große Blöcke reservieren will, deren Größe vielleicht auch von den Eingabedaten abhängt, ist es sicher sinnvoll, vernünftig auf den Fehler zu reagieren.
Wenn es nur um ein paar 20-Byte-Objekte geht, und man unabhängig von den Eingabedaten sicherstellen kann, wie viele es höchstens werden, ist es durchaus legitim, davon auszugehen, dass ein malloc-Fehlschlag entweder ein Problem beim Betriebssystem ist oder ein Bug im eigenen Programm ist. Und dafür eine komplizierte Fehlerbehandlung zu schreiben halte ich für übertrieben. Letztendlich ist das verglichbar mit einem Stacküberlauf, bei dem ja auch das Programm einfach beendet wird, ohne dass noch irgendwas freigegeben wird.
-
collam schrieb:
Was man auch als Fehler ansehen könnte.
Nicht unbedingt, manchmal läuft es eben darauf hinaus, dass man von irgendetwas nur 0 Elemente hat, und NULL ist ein problemlos verwendbarer Zeiger auf ein Array der Länge 0, man kann dann in einer for-Schleife alle 0 Elemente durchlaufen usw., und das Array später auch mit realloc vergrößern.
-
namespace invader schrieb:
Ok, kommt eben darauf an: Wenn man sehr große Blöcke reservieren will, deren Größe vielleicht auch von den Eingabedaten abhängt, ist es sicher sinnvoll, vernünftig auf den Fehler zu reagieren.
Wenn es nur um ein paar 20-Byte-Objekte geht, und man unabhängig von den Eingabedaten sicherstellen kann, wie viele es höchstens werden, ist es durchaus legitim, davon auszugehen, dass ein malloc-Fehlschlag entweder ein Problem beim Betriebssystem ist oder ein Bug im eigenen Programm ist. Und dafür eine komplizierte Fehlerbehandlung zu schreiben halte ich für übertrieben. Letztendlich ist das verglichbar mit einem Stacküberlauf, bei dem ja auch das Programm einfach beendet wird, ohne dass noch irgendwas freigegeben wird.
Full Ack, finde ich ok so (auch, wenn bei uns sogar für kleine 50-Byte-Allokationen die malloc-Rückgabe geprüft wird...).
-
Ich habe es jetzt doch so gelöst, dass ich bei fehlgeschlagenem malloc NULL oder 0 bis in die main zurückgebe und dann halt eben da beende. Mir ist ein fehlgeschlagener malloc zwar auch noch nie untergekommen und ich weiß auch nicht, ob das je passieren wird, allerdings ist bei mir der zu allokierende Speicher eben von den Eingabedaten abhängig und da mache ich dann lieber so eine Abfrage rein. Aber eine "einfache", unumstrittene Lösung scheint es da ja gar nicht so wirklich zu geben.
-
namespace invader schrieb:
collam schrieb:
Was man auch als Fehler ansehen könnte.
Nicht unbedingt, manchmal läuft es eben darauf hinaus, dass man von irgendetwas nur 0 Elemente hat, und NULL ist ein problemlos verwendbarer Zeiger auf ein Array der Länge 0, man kann dann in einer for-Schleife alle 0 Elemente durchlaufen usw., und das Array später auch mit realloc vergrößern.
Der Rückgabewert von malloc ist unbrauchbar, wenn ich malloc mit 0 aufrufe. Warum sollte man es dann tun?
-
plizzz schrieb:
Ich habe es jetzt doch so gelöst, dass ich bei fehlgeschlagenem malloc NULL oder 0 bis in die main zurückgebe und dann halt eben da beende.
Wenn du die Null nicht als Fehlermeldung verwenden kannst, könntest du auch einen weiteren Paramter einführen, einen Zeiger auf eine Variable, in der die Fehlermeldung abgelegt wird. Oder eine globale Variable (globale Variablen sind aber nicht immer eine gute Idee).
plizzz schrieb:
Mir ist ein fehlgeschlagener malloc zwar auch noch nie untergekommen und ich weiß auch nicht, ob das je passieren wird, allerdings ist bei mir der zu allokierende Speicher eben von den Eingabedaten abhängig und da mache ich dann lieber so eine Abfrage rein.
Du kannst einfach nicht wissen, welche Umstände du vorfinden wirst. Vielleicht ist die Ziel-CPU gerade mit der Suche nach einem 17er-Sudoku beschäftigt und hat dafür gerade den ganzen Speicher in Beschlag genommen. Soll schon passiert sein.
plizzz schrieb:
Aber eine "einfache", unumstrittene Lösung scheint es da ja gar nicht so wirklich zu geben.
Zumindest hat sie noch keiner entdeckt. Davon auszugehen, dass malloc() schon nicht NULL liefern wird, ist jedenfalls keine. Wenn du dich andererseits darauf verlassen willst, dass das Betriebssystem irgendwelche Nicht-Standard-Magie macht, bist du im falschen Forum.
Vielleicht kommt ein Garbage Collector deiner Vorstellung von Komfort entgegen:
http://www.hpl.hp.com/personal/Hans_Boehm/gc/Vielleicht ist C auch einfach nicht das passende Werkzeug für deine Aufgabe, üblicherweise ist man in C froh über die manuelle Speicherverwaltung.
-
Nein nein, da verstehst du mich falsch. Ich möchte im Grunde nichts verändern an meiner Speicherverwaltung. Ich wollte lediglich wissen, ob es nicht evtl. eine übersichtlichere Methode gibt, die ganzen malloc-Abfragen zu realisieren, anstatt irgendwelche Rückgabewerte durch die Funktionen durchzureichen. Da es da scheinbar keine eierlegende Wollmilchsau in dieser Angelegenheit gibt, bleibe ich bei dieser Methode und versuche halt, diese sinnvoll einzubinden. Bloß will man es ja doch schon besser machen, wenn es denn besser geht.
-
collam schrieb:
Der Rückgabewert von malloc ist unbrauchbar, wenn ich malloc mit 0 aufrufe. Warum sollte man es dann tun?
Weil es manchmal eleganter ist, als den Fall einer Größe von 0 gesondert behandeln zu müssen. Manchmal hat man eben Datenpakete oder sonstwas der Länge 0, die aber trotzdem nicht komplett unterschlagen werden dürfen.
-
plizzz schrieb:
Ich habe es jetzt doch so gelöst, dass ich bei fehlgeschlagenem malloc NULL oder 0 bis in die main zurückgebe und dann halt eben da beende.
Genau so ist es fein.
plizzz schrieb:
Aber eine "einfache", unumstrittene Lösung scheint es da ja gar nicht so wirklich zu geben.
Doch gibt es. Z.B. aus der main heraus die Funktionen für die Speicherfreigabe aufrufen und mit 'return irgendwas' beenden.
-
namespace invader schrieb:
Manchmal hat man eben Datenpakete oder sonstwas der Länge 0, die aber trotzdem nicht komplett unterschlagen werden dürfen.
Das ist doch Unsinn! Alles was die Länge 0 hat kann unterschlagen werden.
-
namespace invader schrieb:
collam schrieb:
void *m = malloc (length);
if (m == 0)Besser ist stattdessen
if (!m && length)
, da malloc ja NULL zurückgeben kann, wenn man ein Array der Länge 0 haben will.schweres thema, was sagt der standard dazu?
7.20.3 Memory management functions schrieb:
If the space cannot be allocated, a null pointer is returned. If the size of the space requested is zero, the behavior is implementationdefined: either a null pointer is returned, or the behavior is as if the size were some nonzero value, except that the returned pointer shall not be used to access an object.
so wie ich das verstehe, kann das jeder so machen wie er will! hat mich also nicht weiter gebracht...
schauen wir doch mal wie das in der glibc gemacht wurde;)/* Allocate an N-byte block of memory from the heap. If N is zero, allocate a 1-byte block. */ void * rpl_malloc (size_t n) { if (n == 0) n = 1; return malloc (n); }
huch was ist denn das, ein malloc(0) reserviert auch ein char
macht ja auch sinn, denn das ist mehr oder weniger die einzige möglichkeit das relativ sauber über die bühne zu bringen.noch ein kurzer test
#include <stdio.h> #include <stdlib.h> int main() { void *x = malloc(0); if(x==NULL) puts("error"); else puts("no error"); return 0; } ausgabe: "no error"
lg lolo
-
Über die Stelle im Standard gab es schon mal eine Diskussion. Und auch damals habe ich mich gefragt, was man mit dieser Variante (Adresse für Puffer der Länge 0 zurückliefern) eigentlich bezwecken will...
-
_matze schrieb:
Über die Stelle im Standard gab es schon mal eine Diskussion. Und auch damals habe ich mich gefragt, was man mit dieser Variante (Adresse für Puffer der Länge 0 zurückliefern) eigentlich bezwecken will...
NULL ist doch die einzige möglichkeit einen fehler aus der function raus zu bringen, da ja jeder andere wert einen potentiellen speicher bereich darstellt. und ein aufruf mit 0 stellt ja streng genommen keinen fehler dar.
so wie ich das sehe ist der vorschlag von namespace invader "(!m && length)" nicht schlecht aber wenn man die glibc verwendet leider überflüssig...im letzten satz hab ich ja ganz vergessen das wir ja hier im ansi c forum sind
-
plizzz schrieb:
Ich wollte lediglich wissen, ob es nicht evtl. eine übersichtlichere Methode gibt, die ganzen malloc-Abfragen zu realisieren, anstatt irgendwelche Rückgabewerte durch die Funktionen durchzureichen. Da es da scheinbar keine eierlegende Wollmilchsau in dieser Angelegenheit gibt ...
Du hast schon recht, die probate Methode ist das Durchreichen von Errorleveln, weil:
- so goto- Zeugs ist super für lokale Cleanups, exit und anderes Brutalo- Zeugs hilft wenig bei der Fehlersuche.
- Du kannst je nach call depth differenzierte Fehlerbehandlungsstrategien ansetzen.Eigentlich ist es wichtiger, mal ein einheitliches Schema aufzusetzen. Ich bin mal so frech und sage, wenn alles gutgegangen ist, muß man dem nichts hinzufügen und das gibt den Rückgabewert 0. Dann kann ich dem Nicht- Null- Fall zigtausend Infos mitgeben, was gerade gekrackst hat, muß ja nicht nur malloc() sein.
Man kann dadurch an jedem Rückgabelevel entscheiden, was man tun muß und ist nur selten auf Überlegungen angewiesen, was das OS denn jetzt macht.
-
-
plizzz schrieb:
Ich wollte lediglich wissen, ob es nicht evtl. eine übersichtlichere Methode gibt, die ganzen malloc-Abfragen zu realisieren, anstatt irgendwelche Rückgabewerte durch die Funktionen durchzureichen.
Dynamische Sprünge nach aussen gibt es, sind schon erwähnt worden. Ist vielleicht in manchen Fällen besser, als Kaskaden von Wert-Übergaben einzurichten, wenn man in der Mitte gar nichts mit den Werten anstellen will.
_matze schrieb:
Über die Stelle im Standard gab es schon mal eine Diskussion. Und auch damals habe ich mich gefragt, was man mit dieser Variante (Adresse für Puffer der Länge 0 zurückliefern) eigentlich bezwecken will...
Kann mich errinnern. Der Compiler darf dafür sorgen, dass eine Verwaltungsstruktur auf dem Heap erstellt wird, auch wenn der zugehörige Puffer die Länge 0 hat. Der einzige Sinn, den ich bis jetzt dahinter gefunden habe, war, dass damit die Tradition eingehalten wird, möglichst wenige Vorschriften zu machen. Immerhin könnte man sich vielleicht ein paar Prozessor-Takte sparen, wenn man nicht immer prüfen muss, ob der malloc-Parameter 0 ist.
-
noobLolo schrieb:
NULL ist doch die einzige möglichkeit einen fehler aus der function raus zu bringen, da ja jeder andere wert einen potentiellen speicher bereich darstellt. und ein aufruf mit 0 stellt ja streng genommen keinen fehler dar.
Nein, aber er ist sinnlos, wie schon auf der ersten Seite erwähnt wurde.
Ich habe zum Spass mal das gemacht:while(1) void *z = malloc(0);
Bei mir läuft der Speicher ganz langsam voll, VS 2005, ca 1.6 GB nach 5 Minuten.
Da offensichtlich free() bei malloc(0) nötig ist, würde ich lieber sicherstellen, dass im Programm kein malloc(0) vorkommt.
-
Z schrieb:
Bei mir läuft der Speicher ganz langsam voll, VS 2005, ca 1.6 GB nach 5 Minuten.
Wenn malloc(0) nicht NULL zurückgibt, muss man das natürlich wieder freigeben. Wenn malloc(0) NULL zurückgibt, schadet free() aber auch nicht. Am besten ruft man also einfach zu jedem malloc free auf (wäre käme denn auch auf die Idee, das nicht zu tun?)
Wie gesagt kann malloc(0) vorkommen, wenn man sich einfach die Sonderbehandlung des Falls einer Größe von 0 spart.
Zum Beispiel: Man ließt irgendwelche Pakete aus einer Datei, wobei vorher jeweils die Paketgröße selber in der Datei steht. D.h. man ließt die Größe, malloct so viel Speicher, füllt ihn mit fread(buffer,size,1,f), und macht dann irgendwas damit, wobei man natürlich nur auf Arrayindizes 0 <= i < size zugreift.
Und wenn dann mal als Größe 0 gelesen wird (was ja vielleicht im Eingabeformat erlaubt ist) und malloc NULL liefert, funktioniert das immer noch völlig problemlos und standardkonform, ohne dass man diesen Fall gesondert behandelt haben muss.