#c #function-pointers #void-pointers
#c #указатели на функции #пустые указатели
Вопрос:
Я хочу реализовать алгоритм маршевых кубов с использованием c. Этот алгоритм создает поверхность из объема. Иногда функция будет получать массив частиц, описывающий объем, а иногда она будет получать функцию скалярного поля (функция, которая получает некоторое местоположение и возвращает некоторое значение). Вместо создания двух отдельных функций я хочу, чтобы функция marching cubes получала указатель void. Если необходимый метод является поверхностью для частиц, он преобразует указатель в массив частиц, иначе он преобразует его в указатель на функцию. Это иллюстрация того, что я хочу:
particle_array* global_par_array;
double (*global_scalar_field)(location);
double value_according_to_par_array(location loc){
//use the global_par_array and return a value
return value;
}
double value_according_to_scalar_field(location loc){
//use the global_scalar_field and return a value
return value;
}
void marching_cubes(mesh* surface ,void* par_array_or_function, char is_par_array){
// ^ need this argument to
// be dynamically casted
double (*method)(location loc);
if (is_par_array){
global_par_array = (particle_array*)(*par_array_or_function);
method = value_according_to_par_array;
}
else{
global_scalar_field = (double(*)(location))(*par_array_or_function);
method = value_according_to_scalar_field;
}
//do the marching cubes algorithm according to method, changing *surface
return;
Я вызову эту функцию из python (используя ctypes), где я буду отслеживать себя, я имею в виду, что я передам 0
в is_par_array
аргументе, если я передал функцию, приведенную к указателю void, или передам 1
, если я передал массив частиц, приведенный к указателю void, разрешено ли это в c?
Комментарии:
1. Итак, используя простой язык, вы хотели бы передать либо указатель на функцию, либо массив частиц через
void *
тип аргумента, затем привести этот аргумент к его надлежащему типу в зависимости от того, какое значениеis_par_array
имеет?2. @ryyker Да, это то, что я хотел бы сделать.
Ответ №1:
Нет, вы не можете надежно использовать void*
для хранения указателей на функции. void*
является универсальным типом указателя объекта.
Что еще более важно, с точки зрения разработки программы не имеет смысла использовать один и тот же указатель / параметр для совершенно не связанных целей. Правильный способ решить эту проблему — сделать шаг назад и переосмыслить дизайн программы.
Некоторые дизайнерские соображения:
Вы можете использовать void*
для указания на любую структуру, в свою очередь содержащую любой тип, так что это одно очевидное решение. Кроме того, поскольку вы используете те же форматы функций, можно было бы передать функцию в качестве параметра, определяющего функцию. То есть передавать указатель на функцию, который будет использоваться в качестве «обратного вызова». В общем, плохо использовать глобальные переменные, поэтому, если мы сможем это спроектировать, тем лучше.
Я абсолютно не представляю, что делает реальная программа, но вот предлагаемый редизайн с использованием традиционного универсального программирования на C:
typedef double march_cube_t (location, void*);
double march_particle_array (location loc, void* data)
{
// cast data to a struct or object pointer type specific for this function
...
return value;
}
double march_scalar_field (location loc, void* data)
{
// cast data to a struct or object pointer type specific for this function
...
return value;
}
void marching_cubes(mesh* surface, march_cube_t* algo, void* data)
{
...
double result = algo(some_location, data);
}
Также учитывайте постоянную корректность, где это применимо. Если вам не нужно изменять данные, то они должны быть const void*
.
Комментарии:
1. @ryyker Проще говоря, объекты = переменные. Указатели на объекты = указатели на переменные. Указатели на функции = указатели на функции.
2. Они не являются несвязанными целями. Я хочу использовать тот же алгоритм, но изменить способ, которым алгоритм оценивает некоторое местоположение (внутри или снаружи тома). В любом случае я изменю дизайн программы и создам две отдельные функции, спасибо!