2014-05-22 8 views
7

È possibile trovare questo codice nella K & R The C Programming Language:Linea apparentemente non necessaria nell'esempio K & R C per 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 */ 
    } 
} 

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

C'è fondamentalmente una lista collegata, e ogni nodo della lista inizia con un colpo di testa che indica il nodo successivo e la quantità di memoria che il nodo ha allocato dopo l'intestazione (in multipli della dimensione dell'intestazione). Questa lista collegata tiene traccia di dove c'è memoria libera.

Quello che non capisco è perché la linea in "STRANGE LINE ?????" è necessario. Capisco i primi due. Vogliamo fornire all'utente la fine del nodo, quindi riduciamo le dimensioni e anticipiamo lo p con la nuova dimensione e lo assegniamo all'utente (+1). Ma poi la terza riga vuole impostare le dimensioni del posto p punti al numero di unità. Perché? Dopo la seconda riga p punti in un punto nella memoria libera che non sembra avere alcun significato. È una specie di ottimizzazione ingannevole di cui non sono a conoscenza, o è effettivamente necessaria?

Grazie per qualsiasi aiuto!

risposta

7

Il motivo per cui non hai capito questa linea è che non può essere compreso da solo: dal punto di vista di malloc, è inutile. Questa assegnazione viene eseguita per supportare la funzionalità della corrispondente funzione free, che deve conoscere la dimensione allocata per aggiungere il blocco di memoria all'elenco libero.

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

Come si può vedere, la dimensione viene allontanata a scatti nei byte appena prima di ciò che viene restituito al chiamante. Questa è la porzione di intestazione che usa malloc e free per la loro "contabilità".

+0

Risposta perfetta, grazie. Ora vedo anche perché restituiamo 'p + 1' piuttosto che solo' p'! – bombax

+0

perché in 'p' si hanno i metadati che descrivono il blocco assegnato ...' p' è di tipo 'Header', quindi il primo byte" user free "è a' p + 1' –