Wil*_*son 14
这是一个非常广泛的问题.从根本上说,闭包是指令指针以及以正确方式执行指令所需的一些存储上下文.你可以使用结构和函数指针在C中将这样的东西放在一起.
假设你表达一个闭包,它接受两个int并返回void作为结构:
typedef struct VoidClosureIntInt {
void (*fn)(int, int);
int first;
int second;
} VoidClosureIntInt;
Run Code Online (Sandbox Code Playgroud)
并假设你有一个功能:
void Foo(int x, int y);
Run Code Online (Sandbox Code Playgroud)
现在,要创建一个将调用Foo(23,42)的闭包,您可以:
VoidClosureIntInt closure = {&Foo, 23, 42};
Run Code Online (Sandbox Code Playgroud)
然后要执行该闭包,您可以:
(*closure.fn)(closure.first, closure.second);
Run Code Online (Sandbox Code Playgroud)
还有一个问题:大多数情况下,当您使用闭包时,您希望在创建闭包的代码块的生命周期之外传递上下文.(例如:你传递封盖进入,做一些异步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;
}
Run Code Online (Sandbox Code Playgroud)