#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;
}
That's a pretty broad question. Fundamentally a closure is an instruction pointer along with some stored context that's required to execute the instructions in the right way. You can certainly throw something like this together in C using structs and function pointers.
Let's say you express a closure that takes two ints and returns void as a struct:
typedef struct VoidClosureIntInt {
void (*fn)(int, int);
int first;
int second;
} VoidClosureIntInt;
and suppose you have a function:
void Foo(int x, int y);
Now, to create a closure that will invoke Foo(23, 42), you would do:
VoidClosureIntInt closure = {&Foo, 23, 42};
And then to later execute that closure, you would do:
(*closure.fn)(closure.first, closure.second);
One more wrinkle: most of the time when you're using closures, you want to pass context around beyond the lifetime of the code block in which you create the closure. (Example: you're passing the closure into a function that does some asynchronous I/O and will eventually call your closure when that I/O is finished). In such cases, you must be sure to allocate your closure on the heap, and to delete your closure when you're finished with it. (See complete example at the bottom).
One final note: there's obviously a lot of machinery here, and it's just for one kind of closure (a function that takes two integer args and returns void). When I've seen this done in C it's often been done by a code generator that creates machinery for many different kinds of closures. You can also reduce the amount of boilerplate by only supporting closures that take some (fixed number of) void* arguments, and then typecasting within the functions you're using to implement those closures.
If you're in C++, you can take advantage of language features to do this much more generically and with much less typing. See Boost.Function for an example.
Full example:
#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;
}
Scheme 有多种实现,它们被设计为集成为 C 程序的扩展语言。在Scheme 中链接,在Scheme 中编写您的闭包,然后就完成了。
I guess it depends on what your idea of "simple" is.
There are several implementations of Scheme which are designed to be integrated as an extension language for C programs. Link in a Scheme, write your closure in Scheme, and you're done.
发布评论
评论(3)
这是一个相当广泛的问题。从根本上讲,闭包是一个指令指针以及一些以正确方式执行指令所需的存储上下文。您当然可以在 C 中使用结构体和函数指针将类似的东西组合在一起。
假设您表达了一个采用两个 int 并返回 void 作为结构的闭包:
并假设您有一个函数:
现在,要创建一个将调用 Foo(23, 42) 的闭包,您可以执行以下操作:
然后稍后执行该闭包闭包,你会这样做:
还有一个问题:大多数时候,当你使用闭包时,你希望在创建闭包的代码块的生命周期之外传递上下文。 (例如:您将闭包传递给执行一些异步 I/O 的函数,并最终在该 I/O 完成时调用您的闭包)。在这种情况下,您必须确保在堆上分配闭包,并在使用完毕后将其删除。 (请参阅底部的完整示例)。
最后一点:这里显然有很多机制,而且它只是用于一种闭包(一个接受两个整数参数并返回 void 的函数)。当我看到用 C 语言完成此操作时,通常是由代码生成器完成的,该代码生成器为许多不同类型的闭包创建机制。您还可以通过仅支持采用一些(固定数量) void* 参数的闭包来减少样板文件的数量,然后在用于实现这些闭包的函数中进行类型转换。
如果您使用 C++,则可以利用语言功能以更通用的方式完成此操作,并且输入量要少得多。有关示例,请参阅 Boost.Function。
完整示例:
That's a pretty broad question. Fundamentally a closure is an instruction pointer along with some stored context that's required to execute the instructions in the right way. You can certainly throw something like this together in C using structs and function pointers.
Let's say you express a closure that takes two ints and returns void as a struct:
and suppose you have a function:
Now, to create a closure that will invoke Foo(23, 42), you would do:
And then to later execute that closure, you would do:
One more wrinkle: most of the time when you're using closures, you want to pass context around beyond the lifetime of the code block in which you create the closure. (Example: you're passing the closure into a function that does some asynchronous I/O and will eventually call your closure when that I/O is finished). In such cases, you must be sure to allocate your closure on the heap, and to delete your closure when you're finished with it. (See complete example at the bottom).
One final note: there's obviously a lot of machinery here, and it's just for one kind of closure (a function that takes two integer args and returns void). When I've seen this done in C it's often been done by a code generator that creates machinery for many different kinds of closures. You can also reduce the amount of boilerplate by only supporting closures that take some (fixed number of) void* arguments, and then typecasting within the functions you're using to implement those closures.
If you're in C++, you can take advantage of language features to do this much more generically and with much less typing. See Boost.Function for an example.
Full example:
简单的答案:
否
抱歉,除非您将其范围缩小到闭包功能的某种非常小的子集,否则就是这样。
Simple answer:
NO
Sorry, unless you narrow this down to some sort of very small subset of the functionality of closures, that's how it is.
我想这取决于你对“简单”的理解。
Scheme 有多种实现,它们被设计为集成为 C 程序的扩展语言。在Scheme 中链接,在Scheme 中编写您的闭包,然后就完成了。
I guess it depends on what your idea of "simple" is.
There are several implementations of Scheme which are designed to be integrated as an extension language for C programs. Link in a Scheme, write your closure in Scheme, and you're done.