在C中模拟lambdas?

时间:2015-04-03 07:10:43

标签: c lambda code-generation

我应该提到我在C中生成代码,而不是手动执行此操作。我这样说是因为如果背后有很多代码并不重要,因为编译器应该管理它。无论如何,我将如何在C中模拟lambda?我以为我可以在源代码中的某处生成一个带有随机名称的函数然后调用它?我不太确定。我还没有真正尝试过任何事情,因为我想在实施它之前先把它弄清楚。

我可以做某种预处理器指令,还是某种能让这个更清洁的宏?我受到Jon Blow的启发,尝试编译器开发,他似乎用他的语言Jai实现了Lambdas。但是,我认为他做了一些事情,他生成字节码,然后进入C?我不确定。

编辑: 我正在编写一个编译器,编译器只是我的一个让我忙碌的项目,而且我想了解更多有关编译器的知识。我主要使用clang,我在Ubuntu 14.10上。我没有任何垃圾收集,但我想尝试使用某种智能指针-y / rust / ARC启发的内存模型进行垃圾收集,即几乎没有开销。我选择C是因为我想更多地涉足它。我的项目是免费软件,只是一个爱好项目。

1 个答案:

答案 0 :(得分:8)

有几种方法可以做到这一点("在C中有#34; lambdas)。要理解的重要一点是,lambdas给出closures并且闭包正在混合"代码"用"数据" (封闭值);注意到对象也在混合"代码"用"数据"并且对象和闭包之间存在相似性。另请参阅this answer上的Programmers

传统上,在C中,您不仅使用函数指针,而且还采用了关于callbacks约定。例如GTK的情况:每次传递函数指针时,也会传递一些数据。您可以查看回调(给出带有void*数据的C函数指针的约定)作为实现闭包的方法。

由于你生成了C代码(这是一个明智的想法,我在MELT做了类似的事情 - 在Linux-运行时生成C ++代码,将其编译成共享对象,并{{} 1}} - s)你可以采用一个回调约定并将一些封闭的值传递给你生成的每个函数。

您也可以将封闭值视为dlopen变量,但这种方法通常是不明智的。

过去有一些static标头库为闭包生成一个机器特定的trampoline代码(基本上生成一个代码,它将一些封闭的值作为参数推送,然后调用一些例程)。您可以使用一些JIT compilation技术(使用libjit,GNU lightningLLVMasmjit,....)来执行相同操作。另请参阅libffi以调用任意函数(仅在运行时中已知的签名)。

请注意,闭包与garbage collection之间存在强烈但间接的关系(请阅读GC handbook了解更多信息),并且每个functional language都有一个GC并非偶然。 C ++ 11 lambda函数是一个例外(很难理解C ++ 11闭包的内存管理的所有复杂性)。因此,如果您正在生成C代码,您可以并且可能应该使用Boehm's conservative garbage collector(包装lambda.h)并且您将拥有闭包GC-ed值。 (您可以使用其他一些GC库,例如Ravenbrook's MPS或我未维护的Qish ...)然后您可以使用每个生成的C函数将其闭包作为第一个参数的约定。

我建议阅读Scott's book on Programming Language Pragmatics并且(假设你知道一点点Scheme或Lisp;如果你不这样做,你应该学习一点Scheme并阅读{{3} })SICP(如果你碰巧读法语,请阅读最新的法语Queinnec's book Lisp In Small Pieces)。