我最近一直在编写像Lua这样的脚本语言,并且匿名内部函数的存在让我思考。用C语言实现的语言(如Lua)如何在C语言中具有内部函数,无论您做什么,都无法避免在编译期间必须事先声明函数的事实?这是否意味着在C中,实际上有一种方法可以实现内部函数,而这只是实现庞大的代码库以使它们成为可能的问题?
例如
void *block = malloc(sizeof(1) * 1024); // somehow
// write bytes to this memory address to make it operate
// like an inner function?
// is that even possible?
char (*letterFunct)(int) = ((char (*letterFunct)(int))block;
// somehow trick C into thinking this block is a function?
printf("%c\n", (*letterFunct)(5)); // call it
我缺少的关键概念是什么在理解为什么某些具有高级功能的语言(类,对象,内部函数,多线程)可以用没有所有这些语言的语言实现这一差距的桥梁?
答案 0 :(得分:5)
仅仅因为特定语言的编译器/解释器是用C语言编写的,并不意味着该语言必须转换为C然后才能编译。
我不知道Lua,但是在Java的情况下,代码被编译为Java Byte Code,(松散地说)Java VM读取和解释。
原始的C编译器是用汇编语言编写的,原始的C ++编译器是用C语言编写的,因此可以用较低级别的语言编写更高级语言的编译器。
答案 1 :(得分:3)
闭包和内部函数通常涉及将一个额外的(隐藏)参数传递给保存闭包环境的函数。在C中你没有那些隐藏的额外参数,所以要在C中实现闭包或内部函数,你需要使这些额外的参数显式化。所以实现一个"内部功能"在C中,你最终会得到类似的东西:
struct shared_locals {
// locals of function shared with inner function
};
int inner_function(struct shared_locals *sl, /* other args to inner function */...) {
// code for the inner function -- shared locals accessed va sl
}
int function(...) {
struct shared_locals sl; // the shared locals
// call inner function directly
inner_function(&sl, ...);
// pass inner function as a callback
func_with_callback(inner_function, &sl);
}
以上类型的代码是为什么'回调'在C代码中通常涉及函数指针和传递给回调的额外void *
参数。
答案 2 :(得分:1)
要实现内部函数,需要闭包。要实现闭包,您需要一些更高级的机制来分配局部变量而不仅仅是堆栈。 C本来是一种轻量级语言,因此排除了封闭和垃圾收集器等高级概念。
C ++是C的一种扩展,包含所有高级概念,闭包和内部函数。
带有内存块的示例,您使用汇编代码填充:您可以这样做,但它不可移植。这需要来自操作系统和编译器的合作。我能想到的唯一可移植解决方案是将编译器嵌入到每个可执行文件中,这也是太多了。
这仍然是一个正常的非内在功能。要实现在运行时编译的内部函数,您将再次需要闭包。
答案 3 :(得分:1)
Lua是一个程序---就像任何其他程序一样---你运行它,它读取输入,它产生输出。运行lua MyProgram.lua
时,lua
程序从文件MyProgram.lua
读取,并将输出写入控制台。与许多其他程序一样,它吐出的内容取决于它所读取的内容。
lua程序是用C语言编写的。
如果您的MyProgram.lua
文件在顶层包含print("x")
,那么当lua
程序读取该行时,它将打印x
。
注意:
lua
打印x
。它不是真的MyProgram.lua
。MyProgram.lua
只是一个数据文件。lua
程序将其读入,并使用数据来决定它应该做什么。
当lua
程序读取该行时,它不会"翻译"该行成为C或任何其他语言。只是 该行说什么。
它会打印x
。
有一个名称:我们说lua
程序解释 MyProgram.lua
。
注意:我撒了谎。
lua
程序 lua程序只是一个数据文件。当您键入lua MyProgram.lua
时,计算机会将数据读入内存,然后使用数据来决定它应该执行的操作。
当我们谈论计算机系统时,我们会在不同的抽象层次上发言。当我们说,"计算机硬件做X,"我们谈论的是低抽象级别。当我们说" MyProgram.lua
做Z"时,我们谈论的是更高抽象级别。而且,当我们说lua
解释器做了某些事情时,我们正在谈论介于两者之间的某个层面。
在硬件和最终用户体验之间,如果你看起来足够深,你可以找到许多抽象级别。
但是,回到Lua ......
如果您的MyProgram.lua
在顶层包含function p() print("y") end
,则Lua程序不会立即执行任何操作。它只记得你想要p()
的意思。然后,如果它在顶层看到p()
,则然后会打印y
。
您可以用几乎任何语言编写执行这些操作的程序(即,您可以编写Lua
)。您选择使用实现 lua的语言可能会影响Lua解释器的内部体系结构,但它不需要以任何方式限制解释器理解的语言(即Lua语言)。 / p>
答案 4 :(得分:1)
您将C源代码与二进制可执行文件混淆。 Lua解释器(读取和运行Lua脚本的程序)是用C语言编写的。但是在编译之后,它不再是C语言了。如果它是用Fortran编写的(假设它编译为相同的二进制CPU指令),它的行为会相同。
没有“运行C环境”这样的东西。只有二进制机器指令。 CPU不知道C,而不知道法语。
就Lua如何处理内部函数而言,Lua的设计者坐下来想出了解释器遇到内部函数时需要跟踪的所有上下文,并编写代码来汇编和跟踪只要内部功能可行,那就是上下文。内部函数是一个特定的 Lua 构造 - 它与C无关,因为当Lua解释器运行时,任何地方都没有C.