如何在c中模拟闭包

时间:2010-03-20 00:51:33

标签: c closures

有简单的方法吗?

3 个答案:

答案 0 :(得分:14)

这是一个非常广泛的问题。从根本上说,闭包是指令指针以及以正确方式执行指令所需的一些存储上下文。你当然可以使用结构和函数指针在C中抛出这样的东西。

假设您表达了一个带有两个整数的闭包,并将void作为结构返回:

typedef struct VoidClosureIntInt {
  void (*fn)(int, int);
  int first;
  int second;
} VoidClosureIntInt;

并假设你有一个功能:

void Foo(int x, int y);

现在,要创建一个将调用Foo(23,42)的闭包,你可以这样做:

VoidClosureIntInt closure = {&Foo, 23, 42};

然后要执行该闭包,你会这样做:

(*closure.fn)(closure.first, closure.second);

还有一个问题:大多数情况下,当你使用闭包时,你想要在创建闭包的代码块的生命周期之外传递上下文。 (例如:您将闭包传递给执行某些异步I / O的函数,并在I / O完成时最终调用闭包)。在这种情况下,您必须确保在堆上分配闭包,并在完成后删除闭包。 (参见底部的完整示例)。

最后要注意的是:这里显然有很多机器,它只适用于一种闭包(一个带两个整数args并返回void的函数)。当我在C中看到这样做时,它通常由代码生成器完成,该代码生成器为许多不同类型的闭包创建机器。您还可以通过仅支持带有一些(固定数量)void *参数的闭包来减少样板量,然后在您用于实现这些闭包的函数中进行类型转换。

如果您使用的是C ++,那么您可以利用语言功能更加通用,并且输入更少。有关示例,请参阅Boost.Function

完整示例:

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

// Closure support.

typedef struct VoidClosureIntInt {
  void (*fn)(int, int);
  int first;
  int second;
} VoidClosureIntInt;

// The returned closure should be run via RunAndDeleteClosure().
VoidClosureIntInt* NewClosure(void (*fn)(int, int), int first, int second) {
  VoidClosureIntInt* closure = malloc(sizeof(*closure));
  closure->fn = fn;
  closure->first = first;
  closure->second = second;
  return closure;
}

void RunAndDeleteClosure(VoidClosureIntInt* closure) {
  (*closure->fn)(closure->first, closure->second);
  free(closure);
}


// Example use.

void Foo(int x, int y) {
  printf("x=%d\ny=%d\n", x, y);
}

// We take memory ownership of closure.
void SomeAsynchronousFunction(VoidClosureIntInt* closure) {
  RunAndDeleteClosure(closure);
}

int main(int argc, char** argv) {
  VoidClosureIntInt* closure = NewClosure(&Foo, 23, 42);
  SomeAsynchronousFunction(closure);
  return 0;
}

答案 1 :(得分:0)

简单回答:

很抱歉,除非你将其缩小到某种非常小的闭包功能子集,否则就是这样。

答案 2 :(得分:-1)

我想这取决于你对“简单”的看法。

Scheme的几个实现被设计为集成为C程序的扩展语言。在Scheme中链接,在Scheme中编写你的闭包,你就完成了。