2014-10-21 2 views
6

Я пытаюсь получить пример protobuf-c, скомпилированный с помощью компилятора C90 (MS VS2012).Какова цель void * array = * (void **) member + siz * (* p_n);

В исходном коде Protobuf -с есть две C99 конкретные вещи, которые могут быть легко изменены, чтобы быть совместимым с C90, то есть объявление переменной в середине сферы (not allowed in C90) и instantiation of structs через . -syntax (например some_struct_type name = {.a=1,.b=2}).

Я сейчас застрял в одной ошибке компиляции. Соответствующая строка в исходном файле «Protobuf-к.ц» гласит:

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

Где member это определяют как void * и p_n как size_t *. И соответствующая ошибка

error C2036: 'void *' : unknown size 

Пожалуйста, обратите внимание, что это справедливо для Protobuf-с версии 1.0.1 (см respective source code, в строке 2404). Эта линия была изменена в версии 1.0.2 для

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

с this comment. Изменение линии соответственно исключает ошибку компиляции.

Мои вопросы:

  • Я хотел бы понять эту строку кода.
  • Могу ли я перейти на версию *(char **)?
  • Какое сообщение об ошибке говорит мне?

(для какой-то другой причине, я хочу придерживаться Protobuf-с 1.0.1)

+6

Похоже, что он разработан, чтобы быть нечитаемым людьми. :) – Almo

+0

Есть несколько компиляторов, которые обрабатывают void *, аналогичные BYTE *, по крайней мере, в арифметике указателя. то есть sizeof (void *) компилируется в 1. Я бы разделил эту строку беспорядка на ее элементы и заменил 'void *' на 'char *' * для этой конкретной цели арифметики указателя *. – harper

+0

@harper, что бы прочитал код, если бы он был «де-загроможден» – georg

ответ

4

параметр, переданный как member является адресом указателя на указатель на символ. Во-первых, личность и отсрочка получают этот указатель. (Адрес указателя передается так, что указатель может быть изменен в функции.)

Добавление siz * (*p_n) увеличивает указатель на правильный элемент.

Вся линия может быть переписано в виде:

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

Переход от пустоты * на символ * сделано так, что арифметика указателей можно, как C Стандарт не допускает его недействительных указателей. Сообщение об ошибке сообщает вам, что размер объекта void * указывает на неизвестность, так как вам нужно использовать указатель char *.

Пока объект, переданный функции, имеет тип char**, вы можете переключиться на версию **.

2

I would like to understand this line of code.

код делает арифметику указателей и пытается скрыть детали. Поэтому он использует void везде, где указатель не откладывается. Предполагается, что значение sizeof (*(void*)) равно единице.

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

Да, потому что код присваивает полученный указатель и не разыменовывает указатель.

What is the error message telling me?

Этот хак компилятор специфичны. Ваш компилятор не определяет это, он не обеспечивает размер цели void*.

Вы должны использовать «портативную» версию. sizeof(char) - один для большинства компиляторов, и для этих компиляторов он переносимый.