用C中的函数指针定义和调用高阶函数组合函数

时间:2019-11-27 09:53:44

标签: c function function-pointers function-composition

function types上的Wikipedia文章列出了“高阶函数组合函数”的有趣声明:

int (*compose(int (*f)(int), int (*g)(int)))(int);

作为一项学习练习,我想在测试程序中实现此目标,但是失败了,编译器抛出了许多警告和错误。我的尝试:

int a(int x) {
    return x + 1;
}

int b(int x) {
    return x * 2;
}

int (*compose(int (*f)(int y), int (*g)(int z)))(int x) {
    return (*f)(x) - (*g)(x);
}

int main(void) {
    int x = 5;
    int r = (*compose)((*a)(x), (*b)(x))(x);
    printf("Compose result for x = %d: %d\n", x, r);

    return 0;
}

我很高兴能解释一下维基百科的声明与f(g(h(x)))之类的简单函数组成有何不同,以及如何实现,最好是使用类似于我的简单程序。

3 个答案:

答案 0 :(得分:4)

这里有几个问题要解决。

  • 在C语言中,您不能在运行时动态地编写函数。仅在编译时静态地进行。因此,使用为compose选择的签名,您将无法获得所需的运行时合成。如果compose将返回一个(指向a的)函数-它只能返回一个预先存在的函数。 (*)
  • 在C语言中,当您使用函数的标识符(已经定义)时-类型实际上已经是函数指针,即“调用运算符”(或“括号运算符”)始终适用于函数指针。
  • 您的语法有些偏离。

尝试对您的代码进行此修改:

#include <stdio.h> 

int a(int x) {
    return x + 1;
}

int b(int x) {
    return x * 2;
}

int compose(int (*f)(int y), int (*g)(int z), int x) {
    return f(x) - g(x);
}

int main(void) {
    int x = 5;
    int r = compose(a, b, x);
    printf("Compose result for x = %d: %d\n", x, r);

    return 0;
}

compiles

(*)-理论上,您可以执行运行时编译,并返回指向所得机器代码地址的链接,但这不是语言工具。实际上这是无关紧要的

答案 1 :(得分:2)

您的compose函数被声明为返回函数指针,但计算并返回一个int值。

(*a)(x)调用a函数,并将int结果传递给compose,而不是指向函数a本身的指针。与b相同。

要解决您的问题,首先应使用指向函数composea的指针调用b

int r = (*compose(&a, &b))(x);

然后,您需要使compose返回指向函数的指针,其中包括创建要返回的函数:

int (*f1)(int);
int (*f2)(int);

int compose_helper(int x)
{
    return f1(x) - f2(x);
}

int (*compose(int (*f1_)(int), int (*f2_)(int)))(int)
{
    f1 = f1_;
    f2 = f2_;
    return &compose_helper;
}

在C语言中,实际上没有很好的方法,因为函数组合不能在运行时完成,并且需要有全局状态。


作为一个旁注,我真的建议您为功能指针创建类型别名,以使其更易于阅读和理解。

typedef int (fp_type)(int);

fp_type *f1;
fp_type *f2;

fp_type *compose(fp_type *f1_, fp_type *f2_) { ... }

答案 2 :(得分:1)

在C中,您无法在运行时创建新函数; compose只能返回预定义的函数。这是此类功能的简短示例:

int null(int x) { return 0; }
int f1(int x) { return x*x; }
int f2(int x) { return 2*x; }

int sub_f2_f1 ( int x ) { return f2(x)-f1(x); }
int sub_f1_f2 ( int x ) { return f1(x)-f2(x); }
/*...*/

int (*compose(int (*f)(int), int (*g)(int)))(int)
{
  if (f1==f2) return null;
  if (f2==null) return f1;
  if (f==f2 && g==f1) return sub_f2_f1;
  if (f==f1 && g==f2) return sub_f1_f2;
  /*...*/
  return 0;
}