2014-10-21 13 views
6

Ich versuche, ein protobuf-c Beispiel mit einem C90 Compiler (MS VS2012) kompiliert zu bekommen.Was ist der Zweck von void * array = * (void **) member + siz * (* p_n);

Innerhalb der Quellcodes protobuf-c gibt es zwei C99 bestimmte Dinge, die leicht mit C90, dh Variablendeklaration in der Mitte einen Umfang kompatibel zu sein (not allowed in C90) und instantiation of structs über die . -Syntax (zB some_struct_type name = {.a=1,.b=2} geändert werden können).

Ich bin jetzt mit einem Kompilierungsfehler stecken geblieben. Die entsprechende Zeile in der Quelldatei 'protobuf-C.C' lautet:

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

Wo member ist als void * und p_n als size_t * definieren. Und der entsprechende Fehler ist

error C2036: 'void *' : unknown size 

Bitte beachten Sie, dies gilt für protobuf-c Version 1.0.1 (siehe respective source code, in Zeile 2404). Diese Linie wird in Version 1.0.2 zu

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

mit this comment geändert. Wenn Sie die Zeile entsprechend ändern, entfällt der Kompilierungsfehler.

Meine Fragen sind:

  • ich diese Zeile Code verstehen möchten.
  • Kann ich zur *(char **) Version wechseln?
  • Was sagt mir die Fehlermeldung?

(Aus irgendeinem anderen Grund, warum ich protobuf-c 1.0.1 haften möchten)

+6

Sieht aus, als ob es von Menschen nicht lesbar ist. :) – Almo

+0

Es gibt einige Compiler, die void * ähnlich wie BYTE * behandeln, zumindest in der Zeigerarithmetik. d. h. sizeof (void *) kompiliert zu 1. Ich würde diese Clutter-Linie in ihre Elemente aufteilen und 'void *' durch 'char *' * für diesen speziellen Zweck der Zeigerarithmetik * ersetzen. – harper

+0

@harper was würde der Code lesen, wenn er "entstörte" – georg

Antwort

4

Parameter übergeben als member ist eine Adresse eines Zeigers auf Char-Zeiger. Zuerst erhalten die Umwandlung und Defererenz den Zeiger (die Adresse des Zeigers wird übergeben, so dass der Zeiger in der Funktion geändert werden kann).)

Der Zusatz siz * (*p_n) erhöht den Zeiger auf das korrekte Element.

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

Ein Wechsel von void * * auf char gemacht wird, so dass die Zeigerarithmetik möglich ist, wie C Standard auf void-Zeiger nicht erlaubt:

Die ganze Linie könnte als neu geschrieben werden. Die Fehlermeldung besagt, dass die Größe des Objekts, auf das void * zeigt, nicht bekannt ist, da Sie einen char * -Zeiger verwenden müssen.

Solange das an die Funktion übergebene Objekt den Typ char** hat, können Sie zur char ** Version wechseln.

2

I would like to understand this line of code.

Der Code macht Pointer-Arithmetik und versucht, die Details zu verbergen. Daher verwendet es void überall dort, wo der Zeiger nicht deferenziert wird. Die Annahme ist, dass sizeof (*(void*)) gleich Eins ist.

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

Ja, weil der Code die resultierende Zeiger zuweist und dereferenziert nicht den Zeiger.

What is the error message telling me?

Dieser Hack ist Compiler spezifisch. Ihr Compiler hält dies nicht aus, es bietet keine Größe eines void* Ziels.

Sie sollten eine "portable" Version verwenden. Die sizeof(char) ist eine für die meisten Compiler und für diese Compiler ist es tragbar.