2012-12-04 6 views
8

Nella speranza di ottenere una migliore comprensione delle risposte riportate nel this posta, qualcuno può spiegare a me se la seguente implementazione buffer circolare è possibile, e se no, perché no.dereferencing puntatori void

#define CB_TYPE_CHAR  0 
#define CB_TYPE_FLOAT 1 

... 

typedef struct CBUFF 
{ 
    uint16 total;  /* Total number of array elements */ 
    uint16 size;  /* Size of each array element */ 
    uint16 type;  /* Array element type */ 
    uint16 used;  /* Number of array elements in use */ 
    uint16 start;  /* Array index of first unread element */ 
    void *elements;  /* Pointer to array of elements */ 
} CBUFF; 

... 

void cbRead(CBUFF *buffer, void *element) 
{ 
    if (buffer->type == CB_TYPE_CHAR) 
    { 
    /* The RHS of this statement is the problem */ 
     *(char*)element = *(buffer->elements[buffer->start]); 
    } 

    /* Other cases will go here */ 

    buffer->start = (buffer->start + 1) % buffer->total; 

    --buffer->used; 
} 

Capisco che il LHS deve essere gettato a char in modo che io possa dereference il puntatore nullo. Capisco anche che questo codice frammento:

buffer->elements[buffer->start] 

dà l'indirizzo dell'elemento 'buffer-> inizio' degli elementi serie, che anch'io voglio dereference al fine di ottenere il contenuto di quel indirizzo. O almeno questo è quello che prendo da K & R.

Dato tutto questo, come faccio a dire al compilatore che il contenuto della la memoria a quell'indirizzo è un carattere, e che è bene dereferenziarlo ? C'è qualcosa che succede qui, ma non lo capisco, .

+0

Questo codice non viene compilato, lo fa? Il '* (buffer-> elements [buffer-> start])' è un dereferenziamento di un 'void *'. – dasblinkenlight

+0

@dasblinkenlight: Ecco a cosa si riferisce la sua domanda. Penso che abbia tirato il lato sinistro da K & R senza capire appieno cosa fa. –

+0

Zack, il "tipo" del buffer generico viene riparato una volta inizializzato e allocato? Se è così, potresti essere ben servito con un 'union' di tipi di puntatore diversi per rinunciare a tutti i cast del puntatore. – WhozCraig

risposta

12

buffer->elements è anche una void * quindi è necessario lanciare prima di poter fare qualsiasi cosa con esso:

*(char*)element = ((char *)buffer->elements)[buffer->start]; 
+0

Grazie Chris. Non mi rendevo conto che una tale costruzione era possibile. Ho ragione nel leggere questo come dicendo al compilatore che l'array buffer-> elements contiene caratteri, e quindi ottenere il contenuto del buffer-> start nth entry? – Zack

+0

@Zack: sì, è esattamente corretto. Le matrici in C sono veramente trattate come un puntatore al loro primo elemento nella maggior parte dei modi, quindi puoi lanciarlo su un tipo di puntatore diverso e far sì che il compilatore lo tratti come se fosse un tipo di array diverso. –

5

Dato tutto ciò, come faccio a dire al compilatore che il contenuto della memoria a quell'indirizzo è un carattere e che è giusto dereferenziarlo?

Beh, hai già fatto sul lato sinistro di quella linea:

*(char*)element = *(buffer->elements[buffer->start]); 

Per derefence buffer->elements[n] dovrai lanciare quella pure.

*(char*)element = *((char*)buffer->elements)[buffer->start]; 

Ora la domanda è se il cast è corretto o meno. Non posso dirtelo perché non hai pubblicato l'inizializzazione di buffer->elements.

+0

Grazie Ed. Immagino di essere stato confuso da tutte le cose sul RHS. Per quanto riguarda l'inizializzazione, è fatto in una funzione che crea dinamicamente il buffer, imposta il valore di alcuni membri e quindi buffer-> elements = calloc (totale, sizeof (dimensione)); – Zack