首页 > 解决方案 > 我可以动态转换函数参数吗?

问题描述

我想使用 c 实现行进立方体算法。该算法从体积创建表面。有时该函数会接收一个描述体积的粒子数组,有时它会接收一个标量场函数(一个接收某个位置并返回某个值的函数)。我不希望创建两个单独的函数,而是希望行进立方体函数接收一个 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),我将在其中跟踪自己,我的意思是如果我传递了一个强制转换为 void 指针的函数,我将传入0参数is_par_array,或者1如果我传递了一个强制转换为的粒子数组空指针,这在c中是否允许?

标签: cfunction-pointersvoid-pointers

解决方案


不,您不能可靠地使用void*来保存函数指针。void*是通用对象指针类型。

更重要的是,从程序设计的角度来看,将相同的指针/参数用于完全不相关的目的是没有意义的。解决这个问题的正确方法是退后一步,重新思考程序设计。

一些设计思想:
可以使用 avoid*指向任何结构,进而包含任何类型,所以这是一个明显的解决方案。此外,由于您使用相同的函数格式,因此可以将函数作为决定函数的参数传递。也就是说,传递一个函数指针以用作“回调”。一般来说,使用全局变量是不好的,所以如果我们可以设计掉它,那就更好了。

我完全不知道实际程序做了什么,但这里有一个使用 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 的正确性。如果您不需要修改数据,那么这些应该是const void*.


推荐阅读