2014-10-21 21 views
6

Sto cercando di ottenere un esempio protobuf-c compilato con un compilatore C90 (MS VS2012).Qual è lo scopo di void * array = * (void **) member + siz * (* p_n);

All'interno del codice sorgente protobuf-c ci sono due cose C99 specifici che possono essere facilmente modificati per essere compatibile con C90, ossia dichiarazione variabili nel mezzo di portata (not allowed in C90) e instantiation of structs tramite il . -syntax (es some_struct_type name = {.a=1,.b=2}).

Ora sono bloccato con un errore di compilazione rimasto. La rispettiva linea nel file sorgente 'protobuf-ç.ç' si legge:

void *array = *(void **) member + siz * (*p_n); 

Dove member è definiscono void * e p_n come size_t *. e le rispettive errore è

error C2036: 'void *' : unknown size 

Si prega di notare questo vale per protobuf-c versione 1.0.1 (vedi respective source code, alla riga 2404). Questa linea è stata modificata nella versione 1.0.2 per

void *array = *(char **) member + siz * (*p_n); 

con this comment. La modifica della linea di conseguenza elimina l'errore di compilazione.

Le mie domande sono:

  • vorrei capire questa riga di codice.
  • Posso passare alla versione *(char **)?
  • Qual è il messaggio di errore che mi dice?

(per qualche altro motivo che voglio attenersi a protobuf-c 1.0.1)

+6

Sembra che sia progettato per essere illeggibile dagli esseri umani. :) – Almo

+0

Alcuni compilatori trattano il vuoto * simile a BYTE *, almeno nell'aritmetica del puntatore. Ad esempio, sizeof (void *) compila in 1. Vorrei dividere questa riga di clutter nei suoi elementi e sostituire 'void *' con 'char *' * per questo scopo specifico dell'aritmetica del puntatore *. – harper

+0

@harper che cosa leggerebbe il codice se fosse "de-ingombrante" – georg

risposta

4

parametro passato come member è un indirizzo di un puntatore al puntatore del char. Innanzitutto il cast e il defererence ottengono quel puntatore (l'indirizzo del puntatore viene passato in modo che il puntatore possa essere modificato nella funzione.

L'aggiunta siz * (*p_n) incrementa il puntatore all'elemento corretto.

Tutta la linea potrebbe essere riscritto come:

char** pm = member ; 
char* m = *pm ; 
void *array = m + siz * (*p_n); 

Un cambiamento da void * a char * è fatto in modo che l'aritmetica dei puntatori è possibile, come C standard non lo permette su puntatori void. Il messaggio di errore ti dice che, la dimensione dell'oggetto vuoto * sta puntando a non è nota, lì devi usare un puntatore char *.

Fintanto che l'oggetto passato alla funzione ha il tipo char** è possibile passare alla versione char **.

2

I would like to understand this line of code.

il codice effettua l'aritmetica dei puntatori e cerca di nascondere i dettagli. Pertanto utilizza void ovunque il puntatore non sia deferenziato. L'ipotesi è che lo sizeof (*(void*)) sia uguale a uno.

Can I switch to the *(char **) version?

Sì, perché il codice assegna il puntatore risultante e non dereferenzia il puntatore.

What is the error message telling me?

Questo mod è specifica del compilatore. Il tuo compilatore non sottovaluta ciò, non fornisce una dimensione di un target void*.

Si consiglia di utilizzare una versione "portatile". Lo sizeof(char) è uno per la maggior parte dei compilatori e per questi compilatori è portatile.