Spiegazione del codice C.

Qual è il significato del seguente codice:

WORD len; LWORD in; LWORD out; WORD buff_dlen(CBUFF *bp) { return((WORD)((bp->in - bp->out) & (bp->len - 1))); } 

Capisco che bp->in - bp->out significhi differenza tra in e out , ma che rapporto ha con & (bp->len - 1); ?

La funzione restituisce lo spazio disponibile per la lettura in un ring-buffer di una potenza di due dimensioni.

L’operatore & restituirà il valore logico AND (bit per bit) tra i valori bp->in - bp->out e bp->len - 1 .

Elaborando il mio commento: credo che questo frammento provenga da un’implementazione TCP / IP incorporata, trovata in netutil.c . Se questo è corretto, CBUFF è definito in netutil.h come:

 /* Default circular buffer size: MUST be power of 2 ** This definition is for initialisation only, and may be overriden to ** create a larger or smaller buffer. To determine the actual buffer size, all ** functions MUST use the 'len' value below, not the _CBUFFLEN_ definition */ #ifndef _CBUFFLEN_ #define _CBUFFLEN_ 0x800 #endif /* Circular buffer structure */ typedef struct { WORD len; /* Length of data (must be first) */ LWORD in; /* Incoming data */ LWORD out; /* Outgoing data */ LWORD trial; /* Outgoing data 'on trial' */ BYTE data[_CBUFFLEN_]; /* Buffer */ } CBUFF; 

Sembra che i membri in e out siano offset nel buffer, che “puntano” alle posizioni dell’inizio dei dati in entrata e in uscita. Poiché si tratta di un buffer circolare, ci sono due possibilità quando si sottraggono da in (probabilmente come un modo per determinare la lunghezza dei dati in arrivo):

  • in > out : il risultato è un numero positivo inferiore a len . Pertanto, il bitwise & non ha alcun effetto, in quanto qualsiasi numero inferiore a 0x800 anded con 0x7FF è il numero stesso.
  • out > in : In questo caso, il risultato è un numero negativo, compreso tra 0 e -len ; i dati in arrivo ‘avvolgono’ il buffer circolare. Questo è più complicato in quanto si basa su come i numeri negativi sono rappresentati in memoria. Alcuni esempi possono aiutare a chiarire cosa sta accadendo (ricorda che 0x800 in decimale è 2048):
 bp->in-bp->out | representation | &'ed with 0x7FF | decimal representation ----------------+------------------+--------------------+----------------------- -1 | 0xFFFF | 0x07FF | 2047 (2048-1) -2 | 0xFFFE | 0x07FE | 2046 (2048-2) -10 | 0xFFF6 | 0x07F6 | 2038 (2048-10) -2046 | 0xf802 | 0x0002 | 2 (2048-2046) -2047 | 0xf801 | 0x0001 | 1 (2048-2047) 

Come puoi vedere, questa è una tecnica semplice per “scartare” il buffer circolare e recuperare la distanza effettiva tra in e out .