5

我希望能够将函数一般地传递​​给 C 中的函数。我已经使用 C 几年了,并且我知道实现正确的闭包和高阶函数的障碍。这几乎是不可逾越的。

我搜索了 StackOverflow 以了解其他消息来源对此事的看法:

...除了使用可变参数或汇编之外,没有一个通用的答案。我对汇编没有骨气,但如果我能有效地用宿主语言实现一个特性,我通常会尝试。

因为我不能轻易拥有 HOF...

我喜欢高阶函数,但我会在紧要关头接受代表。我怀疑通过下面的代码,我可以在 C 中获得一个可行的委托实现。

想到这样的实现:

enum FUN_TYPES {
    GENERIC,
    VOID_FUN,
    INT_FUN,
    UINT32_FUN,
    FLOAT_FUN,
};

typedef struct delegate {
    uint32 fun_type;
    union function {
        int (*int_fun)(int);
        uint32 (*uint_fun)(uint);
        float (*float_fun)(float);
        /* ... etc. until all basic types/structs in the 
           program are accounted for. */
    } function;
} delegate;

使用示例:

void mapint(struct fun f, int arr[20]) {
    int i = 0;
    if(f.fun_type == INT_FUN) {
        for(; i < 20; i++) {
            arr[i] = f.function.int_fun(arr[i]);
        }
    }
}


不幸的是,这种方法对代表有一些明显的缺点:

  • 没有类型检查,通过检查“fun_type”字段保存你自己做的那些。
  • 类型检查在你的代码中引入了额外的条件,使它比以前更加混乱和多变。
  • 函数的(安全)可能排列的数量受“fun_type”变量的大小限制。
  • 函数指针定义的枚举和列表必须是机器生成的。除了琐碎的情况外,其他任何事情都会接近精神错乱。
  • 遗憾的是,通过普通的 C 语言并不像mov -> 调用序列那样有效,这可能在汇编中完成(有一些困难)。


有谁知道在 C 中做类似委托的更好方法?

注:越便携、越高效越好

另外,注意:我听说过Don Clugston 的 C++ 非常快的代表。但是,我对 C++ 解决方案不感兴趣——只是 C 。

4

2 回答 2

2

您可以为所有函数添加一个void*参数,以允许绑定参数、委托等。不幸的是,您需要为处理外部函数和函数指针的任何内容编写包装器。

于 2013-01-15T05:58:11.430 回答
1

有两个问题我已经研究了类似的技术,提供了稍微不同版本的基本技术。这样做的缺点是您会丢失编译时检查,因为参数列表是在运行时构建的。

首先是我对 Is there a way to do currying in C 的问题的回答。这种方法使用代理函数来调用函数指针和函数的参数。

第二个是我对 C 将参数作为 void-pointer-list 传递给 LoadLibrary() 中的导入函数的问题的回答

基本思想是拥有一个内存区域,然后用于构建参数列表,然后将该内存区域压入堆栈作为函数调用的一部分。结果是被调用函数将内存区域视为参数列表。

在 C 中,关键是定义一个struct包含数组的数组,然后将其用作内存区域。当被调用的函数被调用时,整体struct是按值传递的,这意味着设置到数组中的参数然后被压入堆栈,这样被调用的函数看到的不是一个struct值,而是一个参数列表。

对于 curry 问题的答案,内存区域包含一个函数指针以及一个或多个参数,一种闭包。然后将内存区域交给代理函数,该函数实际上使用闭包中的参数调用该函数。

这是因为标准 C 函数调用将参数压入堆栈,调用函数,当函数返回时,调用者清理堆栈,因为它知道实际压入堆栈的内容。

于 2017-07-25T21:22:15.173 回答