Приведение пустого указателя к указателю произвольного типа - PullRequest
0 голосов
/ 30 января 2012

Я пытаюсь реализовать собственную реализацию общих структур данных в C для собственной учебной выгоды. Мои нынешние усилия - это вектор, и я хочу, чтобы он мог содержать один произвольный тип (или, по крайней мере, размер шрифта, но разве это не все, что действительно имеет значение в C?). Моя структура выглядит следующим образом:

struct vector
{
    void *item;
    size_t element_size;
    size_t num_elements;
}

Однако я не понимаю, как я могу ссылаться на конкретные элементы в массиве * item, если тип должен быть произвольным. Я знаю element_size, но это не помогает мне со ссылками на индексы (например, item [5]), потому что void не является типом. Я подумал, что было бы проще сослаться на элементы как байтовые смещения. Поэтому, если бы я держал вектор структур размером 12, элемент [5] был бы в 12 * 5 = 60 байт от элемента *. Тем не менее, я не понимаю, как получить эти данные. Я знаю, что я хочу 12 байтов из элемента + 60, но как мне заставить компилятор понять это? Я вхожу на территорию препроцессора?

Ответы [ 3 ]

2 голосов
/ 30 января 2012

sizeof - это мера в символах, поэтому вы можете сделать это:

void *start_of_sixth_element = ((char*)item) + (5 * element_size);

Кто-то, кто знает тип каждого элемента, может затем привести start_of_sixth_element к правильному типу, чтобы использовать его.

void* - плохой выбор, поскольку арифметику указателей нельзя использовать с указателями void* в стандартном C (для этого есть расширение GNU, но для переносимого кода вы используете char* или unsigned char* хотя бы для арифметики).

Код, который знает правильный тип до применения смещения 5, может просто сделать это:

correct_type *sixth_element = ((correct_type *)item) + 5;

void не является типом

Это тип, это просто не "полный тип". «Неполный тип» в значительной степени означает, что компилятор не знает, на что действительно указывает void*.

0 голосов
/ 30 января 2012

Таким образом, если бы я держал вектор структур размером 12, элемент [5] был бы на расстоянии 12 * 5 = 60 байт от элемента *.Тем не менее, я не понимаю, как получить эти данные.Я знаю, что я хочу получить 12 байт из элемента + 60, но как мне заставить компилятор это понять?Как вы уже поняли, вам нужно достичь адреса в item + (5 * 12), а затем разыменовать указатель void после приведения его к foo*.

foo my_stuff = *(foo *)(item + 5 * 12);

Вы также можете использовать sizeof(), если вы можете определить при компиляциивремя тип ваших данных:

foo my_stuff = *(foo *)(item + 5 * sizeof(foo));
0 голосов
/ 30 января 2012

void * - это общий тип указателя для любого типа указателя объекта.Вы должны знать, на какой тип он указывает, чтобы правильно привести void * и разыменовать указатель.

Вот пример с объектом void *, используемым с различными типами указателя.

void *p;
int a = 42, b;
double f = 3.14159, g;

p = &a;
b = *(int *) a;

p = &f;
g = *(double *) f; 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...