2015-10-15 3 views
3

У меня есть аналогичная «общая» процедура, такая как qsort, которая имеет указатель на void (указывая на массив), а также параметр указателя функции. Эта функция должна работать на любом типе массива.Как пересечь параметр массива как указатель void

Пример:

void do_something(void * array, int count, int size, void (*test)(const void*)){ 
    int i; 
    for(i=0; i<count; i++){ 
     test(array + (index * size)); 
    } 
} 

Это, однако, дает мне следующее предупреждение (ССАГПЗ test.c -pedantic-ошибки):

error: pointer of type ‘void *’ used in arithmetic [-Wpedantic] 

И после некоторых исследований я узнал, что это плохая практика используйте указатели void как это. (Например, Pointer arithmetic for void pointer in C)

Итак, как стандартная библиотека делает такие вещи, как qsort? Глядя на этот код: (http://aturing.umcs.maine.edu/~sudarshan.chawathe/200801/capstone/n/qsort.c), я вижу следующее:

void 
_quicksort (void *const pbase, size_t total_elems, size_t size, 
     __compar_fn_t cmp) 
{ 
    register char *base_ptr = (char *) pbase; 
    .... 
    char *lo = base_ptr; 
    char *hi = &lo[size * (total_elems - 1)]; 
    ... 
} 

Они литья до (символ *), независимо от фактического типа?

+1

Ну, используя _char_, не больше, независимо от типа, чем с помощью _void_ :) Arthmetic on char выполняет задание (перемещайтесь с шагами _size_). – hexasoft

ответ

3

Я задал аналогичный вопрос Can I do arithmetic on void * pointers in C?.

Void * арифметика не определена. Что значит добавить 1 к указателю на пустоту? Большинство компиляторов (если они разрешают это) обрабатывают его как incrementing sizeof (char) («следующий байт»), но предупреждают вас.

Так что нужно сделать, это явно сделать это делать то, что вы хотите -> литой СИМВОЛ * и приращение, что

+0

Спасибо. Мне также было любопытно, почему вы выбрали char, и я нашел ответ в вашей ссылке: «Тип char удобен, потому что он имеет определенный размер 1 байт». – Aaron

1

Арифметика указателя на неполном типе данных void не является законной, и это то, что компилятор жалуется.

Как вы можете видеть в _quicksort(), указатель является постоянным, так что вы не можете изменить адрес, на который указывает указатель. На указателе void не происходит никаких действий.

1

Making указатель недействительного просто убирает «контекст» указатель - То есть, как система должна смотреть на указатель или на какой бы то ни было указатель.

По этой причине компиляторы не выполняют арифметические действия по указателям на пустоты. Чтобы выполнить арифметику указателя, компилятор должен знать тип указателя, чтобы он мог делать правильные преобразования (если указатель содержит int, он не будет добавлять с 32 битами или, по крайней мере, это позволит вам знаете, что что-то пошло не так!).

По этой причине единственный способ сделать это - направить указатель на что-то и сделать это - я бы не рекомендовал его, если вы не знаете очень хорошо, что получает указатель. Неверные указатели - довольно темное программирование.

+0

Но есть ли другой способ сделать это без указателей пустоты? – Aaron

+0

@Aaron Я считаю, что лучший способ делать вещи - это назначать типы во все времена. Это действительно зависит от того, чего вы пытаетесь достичь. – GrGom

+0

В этом случае это невозможно. – Aaron