"Komfort" bei malloc



  • 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.



  • Z schrieb:

    Da offensichtlich free() bei malloc(0) nötig ist, würde ich lieber sicherstellen, dass im Programm kein malloc(0) vorkommt.

    die sache ist, stell dir vor du gibst eine verkettete liste frei, in dieser liste sind per malloc(x) besorgte speicher blöcke abgelegt, die freigabe routine müßte nun immer checken ob auch was zum freigeben da ist, da ja ein free(NULL) auch was ganz schlimmes ist. also ist eigentlich das problem verschoben...



  • namespace invader schrieb:

    Wie gesagt kann malloc(0) vorkommen, wenn man sich einfach die Sonderbehandlung des Falls einer Größe von 0 spart.

    Das ist wohl Geschmackssache. Ich würde bei Werten aus nicht 100%ig vertrauenswürdiger Quelle immer auf Gültigkeit prüfen:

    size_t n = irgendwo_hergeholt();
    void *a;
    if (n > 0 && n <= MAX)
        a = malloc(n);
    else
       a = 0;  // oder Fehlerbehandlung
    


  • namespace invader schrieb:

    Wie gesagt kann malloc(0) vorkommen, wenn man sich einfach die Sonderbehandlung des Falls einer Größe von 0 spart.

    Das klingt sinnvoll. Passt auch gut zum Standard, der vorschreibt, dass man den Zeiger von malloc(0) in jedem Fall an free() weitergeben darf, weil free(NULL) nichts tut.

    noobLolo schrieb:

    da ja ein free(NULL) auch was ganz schlimmes ist

    Hättest nicht mehr oft umblättern müssen bis:

    TC2 7.20.3.1 schrieb:

    The free function causes the space pointed to by ptr to be deallocated, that is, made
    available for further allocation. If ptr is a null pointer, no action occurs.

    🙂



  • noobLolo schrieb:

    Z schrieb:

    Da offensichtlich free() bei malloc(0) nötig ist, würde ich lieber sicherstellen, dass im Programm kein malloc(0) vorkommt.

    die sache ist, stell dir vor du gibst eine verkettete liste frei, in dieser liste sind per malloc(x) besorgte speicher blöcke abgelegt, die freigabe routine müßte nun immer checken ob auch was zum freigeben da ist, da ja ein free(NULL) auch was ganz schlimmes ist. also ist eigentlich das problem verschoben...

    habs gerade nochmal getestet, free(0) geht, hab das iwie mit uninitialisierten pointern vertauscht

    void *p;
    free(p);
    

    => *boom*

    lg lolo



  • Z schrieb:

    while(1)
          void *z = malloc(0);
    

    Bei mir läuft der Speicher ganz langsam voll, VS 2005, ca 1.6 GB nach 5 Minuten.

    Könnte mir jemand das erklären wieso das so ist? 😞
    Das ist irgendwie interessant auch wenn es blödsinnig aussieht.



  • woooooah schrieb:

    Z schrieb:

    while(1)
          void *z = malloc(0);
    

    Bei mir läuft der Speicher ganz langsam voll, VS 2005, ca 1.6 GB nach 5 Minuten.

    Könnte mir jemand das erklären wieso das so ist? 😞
    Das ist irgendwie interessant auch wenn es blödsinnig aussieht.

    wieso postest du in einen thread den du nicht gelesen hast? 🙄



  • noobLolo schrieb:

    wieso postest du in einen thread den du nicht gelesen hast? 🙄

    Ich hab den thread gelesen aber ich verstehe nicht wieso 0 bytes auch eine größe ist. was wird da angefordert?



  • evtl. hast auch ein problem mit deinem englisch 😕

    noobLolo schrieb:

    ...
    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);
    }
    

    ...



  • danke nooblolo 🙂
    hab es aus dem thread nicht rauslesen können!



  • heyhoi schrieb:

    Ich hab den thread gelesen aber ich verstehe nicht wieso 0 bytes auch eine größe ist. was wird da angefordert?

    Nichts. Was die Gnu libc tut, kannst du getrost ignorieren, ist ja keine Referenz-Implementation. Den Speicher verbraucht in dem Fall grossteils/ausschliesslich der Overhead.
    🙂



  • Wird malloc() mit der Länge 0 aufgerufen ist vorher etwas schiefgelaufen.
    Der Fall sollte normaerweise nicht auftreten bzw es sollte vorher geprüft
    und reagiert werden.

    Kann das OS den Speicher nicht bereitstellen ist es so gut wie immer
    sinnfrei, das Programm weiterlaufen zu lassen. Wozu auch ?
    Also: exit() und raus.

    Da der Fall äußerst selten vorkommt (ok, bei mir. Mag bei anderen anders
    aussehen) ignoriere ich "Nebeneffekte". Da soll sich das OS drum kümmern.


Anmelden zum Antworten