C 中的通用函数指针

发布于 2024-08-25 13:20:21 字数 695 浏览 9 评论 0原文

我有一个函数,它接受一个数据块和该块的大小以及一个函数指针作为参数。然后它迭代数据并对数据块的每个元素执行计算。 以下是我正在做的事情的基本概要:

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;
} 

这运行良好,但现在我需要将一个附加变量传递给我的函数指针。 有没有

int mynewcalculation(int input, int someVariable){
    //e.g.
    input = input * someVariable;
    //...
    return input;
}

一种优雅的方式来实现这一点,同时保持我的整体设计理念?

I have a function which takes a block of data and the size of the block and a function pointer as argument. Then it iterates over the data and performes a calculation on each element of the data block.
The following is the essential outline of what I am doing:

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]);
    }
}

The functions I am passing as arguments look something like this:

int mycalculation(int input){
    //doing some math with input
    //...
    return input;
} 

This is working well, but now I need to pass an additional variable to my functionpointer. Something along the lines

int mynewcalculation(int input, int someVariable){
    //e.g.
    input = input * someVariable;
    //...
    return input;
}

Is there an elegant way to achieve this and at the same time keeping my overall design idea?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

┾廆蒐ゝ 2024-09-01 13:20:21

使其完全通用的常用方法是使用 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* 也不会添加任何额外的代码行;它被干净地传递了,用户只需将其取消引用为(希望)正确的类型(在一般情况下,这可能是一个结构体)。

The usual way to make it totally generic is with a void*, which of course causes all kinds of typesafety issues:

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);
}

Any given function to be passed in must have that prototype, but you can shove any data you want in through userdata. There's just absolutely no typechecking.

You could also use va_args as dbingham suggests; this isn't really much different though, since the prototype for your function to map will have to be int(int, va_list).

Edit: I favor the void* approach. The va_list doesn't add any typesafety anyway and adds more potential for user error (particularly calling va_end twice or not implementing the va_arg loop right). The void* also doesn't add any extra lines of code; it's passed cleanly through, and the user just dereferences it into (hopefully) the right type (which is probably a struct, in the general case).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文