2014-05-22 11 views
7

Można znaleźć ten kod w K & R: C Programming Language:Pozornie niepotrzebna linia w przykładzie K & R C dla malloc?

void *malloc(unsigned nbytes) { 
    Header *p, *prevp; 
    Header *moreroce(unsigned); 
    unsigned nunits; 

    nunits = (nbytes+sizeof(Header)-1)/sizeof(header) + 1; 
    if ((prevp = freep) == NULL) { /* no free list yet */ 
     base.s.ptr = freeptr = prevptr = &base; 
     base.s.size = 0; 
    } 
    for (p = prevp->s.ptr; ; prevp = p, p = p->s.ptr) { 
     if (p->s.size >= nunits) { /* big enough */ 
      if (p->s.size == nunits) { /* exactly */ 
       prevp->s.ptr = p->s.ptr; 
      } else { /* allocate tail end */ 
       p->s.size -= nunits; 
       p += p->s.size; 
       p->s.size = nunits; /* STRANGE LINE???????? */ 
      } 
      freep = prevp; 
      return (void *)(p+1); 
     } 
     if (p == freep) /* wrapped around free list */ 
      if ((p = morecore(nunits)) == NULL) 
       return NULL; /* none left */ 
    } 
} 

(od http://pelusa.fis.cinvestav.mx/tmatos/LaSumA/LaSumA2_archivos/Supercomputo/The_C_Programming_Language.pdf)

Jest to w zasadzie połączonej listy, a każdy węzeł w liście zaczyna się od nagłówka wskazujący następny węzeł i ilość pamięci przydzielonej przez węzeł po nagłówku (w wielokrotnościach rozmiaru nagłówka). Ta połączona lista śledzi, gdzie jest wolna pamięć.

Co ja nie rozumiem, dlaczego linia na „dziwne LINE ?????” jest potrzebne. Rozumiem dwa pierwsze. Chcemy dać koniec węzła do użytkownika, więc zmniejszyć rozmiar i awansować p z nowego rozmiaru i podać, że dla użytkownika (+1). Ale trzecia linia chce ustawić rozmiar miejsca na p na liczbę jednostek. Czemu? Po drugiej linii p wskazuje miejsce w wolnej pamięci, które nie ma żadnego znaczenia. Czy jest to jakaś sztuczna optymalizacja, której nie jestem świadomy, czy jest to rzeczywiście konieczne?

Dzięki za wszelką pomoc!

Odpowiedz

7

Powodem nie rozumieli tej linii jest to, że nie można zrozumieć w oderwaniu: z punktu widzenia malloc, nie ma sensu. To zadanie jest wykonywane w celu obsługi funkcji odpowiadającej mu funkcji free, która musi znać przydzielony rozmiar, aby dodać porcję pamięci do wolnej listy.

void free(void *ap) 
{ 
    Header *bp, *p; 
    bp = (Header *)ap - 1; /* point to block header */ 
    for (p = freep; !(bp > p && bp < p->s.ptr); p = p->s.ptr) 
     if (p >= p->s.ptr && (bp > p || bp < p->s.ptr)) 
      break; /* freed block at start or end of arena */ 
    /* Here is where the saved size comes into play */ 
    if (bp + bp->size == p->s.ptr) { /* join to upper nbr */ 
     bp->s.size += p->s.ptr->s.size; 
     bp->s.ptr = p->s.ptr->s.ptr; 
    } else 
     bp->s.ptr = p->s.ptr; 
    if (p + p->size == bp) { /* join to lower nbr */ 
     p->s.size += bp->s.size; 
     p->s.ptr = bp->s.ptr; 
    } else 
     p->s.ptr = bp; 
    freep = p; 
} 

Jak widać, wielkość jest Squirreled daleko w bajtach tuż przed co wrócił do rozmówcy. Jest to część nagłówka, która jest używana do ich "księgowania".

+0

Doskonała odpowiedź, dzięki. Teraz widzę też, dlaczego zwracamy 'p + 1' zamiast tylko' p'! – bombax

+0

bo w 'p' masz metadane opisujące przydzielony kawałek ...' 'p' jest typu Header', to pierwszy„free user”bajt jest' p + 1 ' –