Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/58.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 如何生成返回函数的函数?_C_Function_Pointers_Modularity - Fatal编程技术网

C 如何生成返回函数的函数?

C 如何生成返回函数的函数?,c,function,pointers,modularity,C,Function,Pointers,Modularity,大图:我有一个带函数的模块,还有一个在这些函数上带有过程和函数的模块 当我组合两个函数时(从函数的模块接口): 在几个方面,(其中一个是添加): 以下(部分)实现没有问题: z1 = (*f)(param1, x); z2 = (*g)(param2, x); y = z1 + z2; return y; 但当我想返回指向“新”函数的指针时,类似于: void *OP_PAdd( double (*f)(double,double), double param3 ); 我不能让它正常工作,也

大图:我有一个带函数的模块,还有一个在这些函数上带有过程和函数的模块

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

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

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

z1 = (*f)(param1, x);
z2 = (*g)(param2, x);
y = z1 + z2;
return y;
但当我想返回指向“新”函数的指针时,类似于:

void *OP_PAdd( double (*f)(double,double), double param3 );

我不能让它正常工作,也不能打正确的“电话”。我想在其他函数中使用输出“函数”作为输入。

当从另一个函数返回函数时,最干净的方法是使用
typedef

typedef double (*ftype)(double, double);
然后您可以这样声明您的函数:

ftype OP_PAdd( ftype f, double param3 )
{
    ....
    return f1;
}
typedef double ftype(double, double);
您可以在不使用
typedef
的情况下执行此操作,但它很混乱:

double (*OP_PAdd( double (*f)(double,double), double param3 ))(double,double)
{
    return f1;
}
因此,当您将函数指针用作其他函数的参数或返回值时,请使用
typedef

编辑:

虽然您可以这样声明类型:

ftype OP_PAdd( ftype f, double param3 )
{
    ....
    return f1;
}
typedef double ftype(double, double);
在实践中,您永远不能直接使用这样的类型。函数不能返回函数(只返回函数的指针),并且不能将此类型的变量赋值给

此外,您不需要显式地取消引用函数指针来调用函数,因此指针本身是隐藏的这一事实并不是什么大问题。将函数指针定义为
typedef
也是惯例。从:

#包括
类型定义无效(*sighandler_t)(内部);
信号机(内部信号机、信号机);

你的意思是这样的吗?
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;
}
编辑:@dbush-answer下的注释之后,此版本将从
typedef
作为指针返回到函数。它给出了相同的输出,但在
decider()
中,无论我是否编写
返回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;
}
#包括
#包括
typedef-double(乐趣)(double,double);
双加(双a,双b){
返回a+b;
}
双接头(双a、双b){
返回a-b;
}
双mul(双a、双b){
返回a*b;
}
乐趣*决策者(字符操作){
开关(op){
案例“+”:return add;//return&add;
案例'-':返回子节点;
案例“*”:返回mul;
}
出口(1);
}
内部主(空)
{
fun*foo;
foo=决策者('+');
printf(“%f\n”,foo(42.0,24.0));
foo=决策者('-');
printf(“%f\n”,foo(42.0,24.0));
foo=决策者('*');
printf(“%f\n”,foo(42.0,24.0));
返回0;
}

在C中,您可以返回指向函数的指针,但要做到这一点,函数首先需要存在,而且动态创建函数不是C所说的可能,更不用说如何实现了

如果您的代码只在一个操作系统和一个处理器上工作(可能还有一些其他限制),您可以:

  • 分配内存页
  • 编写数据和机器代码,执行所需操作,调用指针传递的函数等
  • 将内存保护从读/写更改为读/执行
  • 返回指向已创建函数的指针
  • 不要担心每个函数需要4kB

  • 可能有这样的库,但不一定是可移植的

    其他答案是正确和有趣的,但您应该知道,在可移植C99中,不可能有真正的as C函数(这是C的一个基本限制)。如果您不知道闭包是什么,请仔细阅读关于闭包的wiki页面(并阅读,尤其是其)。但是请注意,在中,确实有闭包,使用和。大多数其他编程语言(Ocaml、Haskell、Javascript、Lisp、Clojure、Python等)都有闭包

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

    有时,您可以在运行时生成一个C函数(使用非标准特性,可能需要操作系统或某些外部库的帮助)。您可以使用一些库,例如,(两者都将快速生成一些运行缓慢的代码),(您将显式生成每个机器指令,并且您有责任发出快速x86-64代码),或者(两者都在现有编译器之上,因此可以用来发出一些优化的代码,速度稍微慢一点)。在POSIX和Linux系统上,您还可以在一些临时文件
    /tmp/tempcode.C
    中发出一些C代码,将该代码的编译(例如
    gcc-fPIC-Wall-O2-shared/tmp/tempcode.C-o/tmp/tempcode.so
    )放入插件中,并使用&


    我们不知道你所编码的实际应用程序是什么,但是你可以考虑在其中嵌入一些解释器,例如。然后,您将使用并向嵌入式计算器/解释器提供回调。

    我在这里会非常恼火,所以请保持冷静

    标准的C api附带了两个函数,分别称为
    setjmp
    longjmp
    。撇开糟糕的命名不谈,它们基本上是将当前状态的副本(包括堆栈位置和寄存器值)存储到
    jmp_buf
    (或者,技术名称是
    continuation
    )中

    66.000000
    18.000000
    1008.000000
    
    #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;
    }
    
    jmp_buf jb;
    
    void sfunc(void) {
        void *sp_minus1 = 0xBEEFBABE;
        setjmp(jb);
    }
    
    #include <inttypes.h>  // intptr_t
    #include <setjmp.h>    // longjmp, setjmp
    #include <stdio.h>     // printf
    #include <stdlib.h>    // malloc, free
    #include <string.h>    // memcpy
    
    
    typedef struct {
        jmp_buf jb;
        int fixupc;
        int fixupv[10];
        size_t stack_size;  // this is only an approximation
        void *stack_ptr;
    } CLOSURE;
    
    
    int getclosure(CLOSURE *closure) {
        unsigned int i, size;
        void *i_ptr = &i, *sp;
        unsigned char *data = (unsigned char *)(void *)closure->jb;
        memset(closure, 0, sizeof(CLOSURE));
        if (!setjmp(closure->jb)) {
            printf("looking for 0x%08X...\n\n", (unsigned int)(intptr_t)i_ptr);
            for (i = 0; i < sizeof(closure->jb); i++) {
                memcpy(&sp, &data[i], sizeof(void *));
                size = (unsigned int)(intptr_t)(sp - i_ptr);
                if (size < 0x300) {
                    closure->fixupv[closure->fixupc++] = i;
                    printf("  fixup @ 0x%08X\n", (unsigned int)(intptr_t)sp);
                    if (sp > closure->stack_ptr) {
                        closure->stack_size = size;
                        closure->stack_ptr = sp;
                    }
                }
            }
            if (!closure->stack_ptr)
                return 0;
            printf("\nsp @ 0x%08X\n", (unsigned int)(intptr_t)closure->stack_ptr);
            printf("# of fixups = %i\n", closure->fixupc);
            /*
             * once we allocate the new stack on the heap, we'll need to fixup
             * any additional stack references and memcpy the current stack.
             *
             * for the sake of this example, I'm only fixing up the pointer
             * to the stack itself.
             *
             * after that, we would have successfully created a closure...
             */
             closure->stack_size = 1024;
             sp = malloc(closure->stack_size);
             memcpy(sp, closure->stack_ptr, closure->stack_size);
             memcpy(&data[closure->fixupv[0]], &sp, sizeof(void *));
             closure->stack_ptr = sp;
             return 1;
        } else {
            /*
             * to this bit of code right here
             */
            printf("holy shit!\n");
            return 0;
        };
    }
    
    void newfunc(CLOSURE *closure) {
        longjmp(closure->jb, 1);
    }
    
    void superfunc(CLOSURE *closure) {
        newfunc(closure);
    }
    
    int main(int argc, char *argv[]) {
        CLOSURE c;
        if (getclosure(&c)) {
            printf("\nsuccess!\n");
            superfunc(&c);
            free(c.stack_ptr);
            return 0;
        }
        return 0;
    }
    
    double retfunc()
    {
       return 0.5;
    }
    
    double (*fucnt)()
    {
      return retfunc;
    }
    
    main()
    {
       printf("%f\n", (*funct())());
    }
    
    jmp_buf jb;
    
    void *myfunc(void) {
        static struct {
            // put all of your local variables here.
            void *new_data, *data;
            int i;
        } *_;
        _ = malloc(sizeof(*_));
        _.data = _;
        if (!(_.new_data = (void *)(intptr_t)setjmp(jb)))
            return _.data;
        _.data = _.new_data;
        /* put your code here */
        free(_);
        return NULL;
    }
    
    void *data = myfunc();
    longjmp(jb, (int)(intptr_t)data);