使用联合和函数指针在C中实现函数委托

时间:2013-01-15 05:52:54

标签: c delegates function-pointers anonymous-function unions

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

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

......除了使用varargs或汇编之外,没有人有一个银弹通用答案。我没有装配的骨头,但如果我能用主语言有效地实现一个功能,我通常会尝试。

因为我不能轻易拥有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 - &gt;那样有效率。调用序列,这可能是在汇编中完成的(有些困难)。


有没有人知道更好的方法来做像C中的代表?

注意:越便携,越高效越好

另外,注意:我听说过Don Clugston's very fast delegates用于C ++。但是,我对C ++解决方案不感兴趣 - 只是C。

2 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分:0)

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

第一个是my answer to the question of Is there a way to do currying in C。此方法使用代理函数来调用函数指针和函数的参数。

第二个是my answer to the question C Pass arguments as void-pointer-list to imported function from LoadLibrary()

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

在C中,关键是定义一个struct,其中包含一个数组,然后将其用作存储区。当调用被调用函数时,整个struct将通过值传递,这意味着设置到数组中的参数然后被推送到堆栈,以便被调用函数看不到struct值,而是参数列表。

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

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