我有一个函数,它接受一个数据块和块的大小和一个函数指针作为参数。然后,它迭代数据并对数据块的每个元素进行计算。
以下是我正在做的事情的基本概要:
int myfunction(int* data, int size, int (*functionAsPointer)(int)){
//walking through the data and calculating something
for (int n = 0; n < size; n++){
data[n] = (*function)(data[n]);
}
}
我作为参数传递的函数看起来像这样:
int mycalculation(int input){
//doing some math with input
//...
return input;
}
这很好用,但现在我需要将另一个变量传递给我的functionpointer。一切顺利
int mynewcalculation(int input, int someVariable){
//e.g.
input = input * someVariable;
//...
return input;
}
是否有一种优雅的方式来实现这一目标,同时保持我的整体设计理念?
使其完全通用的通常方法是使用void *,这当然会导致各种类型的安全问题:
int map_function(int* data, int size, int (*f_ptr)(int, void*), void *userdata){
//walking through the data and calculating something
for (int n = 0; n < size; n++){
data[n] = (*f_ptr)(data[n], userdata);
}
}
int simple_calculation(int input, void *userdata) {
// ignore userdata and do some math with input
return input;
}
int calculation_with_single_extra_arg(int input, void *userdata) {
int input2 = * (int*) userdata;
// do some math with input and input2
return input;
}
int calculation_with_many_extra_args(int input, void *userdata) {
my_data_t data = (my_data_t *) userdata;
return input * (input * data->a + data->b) + data->c;
}
int main(int argc, char **argv) {
int array[100];
my_data_t userdata = { 1, 2, 3 };
populate(array, 100);
map_function(data, calculation_with_many_extra_args, &userdata);
}
要传入的任何给定函数都必须具有该原型,但您可以推送所需的任何数据 userdata
。绝对没有类型检查。
你也可以像dbingham所说的那样使用va_args;但这并没有太大的不同,因为你要映射的函数的原型必须是 int(int, va_list)
。
编辑:我赞成 void*
做法。该 va_list
无论如何都不会增加任何类型的安全性并增加用户错误的可能性(特别是呼叫 va_end
两次或没有实施 va_arg
循环右)。 void *也不会添加任何额外的代码行;它通过干净利落,并且用户只需将其解引用(希望)正确的类型(在一般情况下可能是结构)。