如何创建一个返回函数的函数?

MCL*_*MCL 40 c pointers modularity function

大图:我有一个带有功能的模块和一个带有这些功能的程序和功能的模块.

当我组合两个函数时(来自函数的模块接口):

double f1(double alpha, double x);
double f2(double beta, double x);
Run Code Online (Sandbox Code Playgroud)

在几个方面,(其中一个是添加):

double OP_Addition(double (*f)(double,double) , double (*g)(double,double), double param1, double param2, double x);
Run Code Online (Sandbox Code Playgroud)

以下(部分)实现没有问题:

z1 = (*f)(param1, x);
z2 = (*g)(param2, x);
y = z1 + z2;
return y;
Run Code Online (Sandbox Code Playgroud)

但是当我想返回指向"新"函数的指针时,类似于:

void *OP_PAdd( double (*f)(double,double), double param3 );
Run Code Online (Sandbox Code Playgroud)

我无法让它正常工作,也没有做出正确的"通话".我想在其他函数中使用输出"function"作为输入.

dbu*_*ush 32

从另一个函数返回函数时,最简单的方法是使用typedef:

typedef double (*ftype)(double, double);
Run Code Online (Sandbox Code Playgroud)

然后你可以像这样声明你的函数:

ftype OP_PAdd( ftype f, double param3 )
{
    ....
    return f1;
}
Run Code Online (Sandbox Code Playgroud)

你可以在没有a的情况下做到这一点typedef,但它很麻烦:

double (*OP_PAdd( double (*f)(double,double), double param3 ))(double,double)
{
    return f1;
}
Run Code Online (Sandbox Code Playgroud)

因此,当您将函数指针作为参数或返回其他函数的值时,请使用a typedef.

编辑:

虽然你可以声明这样的类型:

typedef double ftype(double, double);
Run Code Online (Sandbox Code Playgroud)

在实践中,你永远不能直接使用这样的类型.函数不能返回函数(仅指向函数的指针),并且不能将此类型的变量赋值给.

此外,您不需要显式取消引用函数指针来调用函数,因此指针本身被隐藏的事实不是一个大问题.将函数指针定义为a也是惯例typedef.从手册页signal:

   #include <signal.h>

   typedef void (*sighandler_t)(int);

   sighandler_t signal(int signum, sighandler_t handler);
Run Code Online (Sandbox Code Playgroud)

  • 一般来说,在typedef中隐藏指针并不是一个好主意.但功能的情况下,这是不可避免的.没有函数类型这样的东西,只有指向函数的指针. (11认同)
  • 废话:`typedef double ftype(double,double); ftype*OP_PAdd(ftype*f,double param3);` (7认同)
  • 我不喜欢隐藏typedef背后的指针.我认为最好使`ftype`成为一个实际的函数类型,然后返回`ftype*`. (2认同)

Bas*_*tch 25

其他答案是正确和有趣的,但你应该知道在便携式C99中,没有办法将真正的闭包作为C函数(这是C的一个基本限制).如果你不知道什么是封,读仔细对他们的wiki页面(也读SICP,尤其是其§1.3).但请注意,在C++ 11中,您使用std :: functionlambda-expressions进行闭包.大多数其他编程语言(Ocaml,Haskell,Javascript,Lisp,Clojure,Python,......)都有闭包.

由于C中缺少真正的闭包("数学上"C函数中唯一的闭合值是全局或静态变量或文字),大多数接受C函数指针的库都提供了一些带有一些客户端数据的API处理回调(一个简单的例子可能是qsort_r,但更严肃地看看GTK内部).客户端数据(通常是不透明指针)可用于保持闭合值.您可能希望遵循类似的约定(因此系统地将函数指针作为带有一些额外客户端数据的回调传递),因此您需要更改C函数的签名(而不是只传递原始函数指针,您将通过函数指针和一些客户端数据作为回调,以"模拟"闭包.

有时您可以在运行时生成C函数(使用非标准功能,可能在操作系统或某些外部库的帮助下).您可以使用一些JIT编译库,例如GNU lightning,libjit(两者都会快速生成一些运行缓慢的代码),asmjit(您将明确生成每个机器指令,并且您有责任发出快速的x86-64代码),GCCJITLLVM(两者都在现有的编译器之上,所以可以用来缓慢地发出一些优化的代码).在POSIX和Linux系统上,您还可以在一些临时文件中发出一些C代码,将该代码/tmp/tempcode.c的编译(例如gcc -fPIC -Wall -O2 -shared /tmp/tempcode.c -o /tmp/tempcode.so)分成一个插件,并使用dlopen(3)dlsym(3)动态加载生成的插件.

顺便说一下,我们不知道您编写的实际应用程序是什么,但您可以考虑在其中嵌入一些解​​释器,例如LuaGuile.然后,您将使用并向嵌入式评估程序/解释程序提供回调.


Wea*_*ane 13

你的意思是这样的吗?该decider()函数返回指向另一个函数的指针,然后调用该函数.

#include <stdio.h>
#include <stdlib.h>

typedef double(*fun)(double, double);

double add(double a, double b) {
    return a + b;
}

double sub(double a, double b) {
    return a - b;
}

double mul(double a, double b) {
    return a * b;
}

fun decider(char op) {
    switch(op) {
        case '+': return add;
        case '-': return sub;
        case '*': return mul;
    }
    exit(1);
}

int main(void)
{
    fun foo;

    foo = decider('+');
    printf("%f\n", foo(42.0, 24.0));

    foo = decider('-');
    printf("%f\n", foo(42.0, 24.0));

    foo = decider('*');
    printf("%f\n", foo(42.0, 24.0));

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

节目输出:

66.000000
18.000000
1008.000000
Run Code Online (Sandbox Code Playgroud)

编辑:@dbush答案下的评论之后,这个版本从typedef作为指针退回到一个函数.它提供相同的输出,但在decider()它中编译干净并提供正确的输出,无论我是否写return add;return &add;

#include <stdio.h>
#include <stdlib.h>

typedef double(fun)(double, double);

double add(double a, double b) {
    return a + b;
}

double sub(double a, double b) {
    return a - b;
}

double mul(double a, double b) {
    return a * b;
}

fun *decider(char op) {
    switch(op) {
        case '+': return add;     // return &add;
        case '-': return sub;
        case '*': return mul;
    }
    exit(1);
}

int main(void)
{
    fun *foo;

    foo = decider('+');
    printf("%f\n", foo(42.0, 24.0));

    foo = decider('-');
    printf("%f\n", foo(42.0, 24.0));

    foo = decider('*');
    printf("%f\n", foo(42.0, 24.0));

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

  • @WeatherVane编译器知道区别.后者将生成一个警告:`format'%s'需要类型'char*',但参数2的类型为'char(*)[6]'` (2认同)