第24章 C API纵览 |
Lua是一个嵌入式的语言,意味着Lua不仅可以是一个独立运行的程序包也可以是一个用来嵌入其他应用的程序库。你可能觉得奇怪:如果Lua不只是独立的程序,为什么到目前为止贯穿整本书我们都是在使用Lua独立程序呢?这个问题的答案在于Lua解释器(可执行的lua)。Lua解释器是一个使用Lua标准库实现的独立的解释器,她是一个很小的应用(总共不超过500行的代码)。解释器负责程序和使用者的接口:从使用者那里获取文件或者字符串,并传给Lua标准库,Lua标准库负责最终的代码运行。
Lua可以作为程序库用来扩展应用的功能,也就是Lua可以作为扩展性语言的原因所在。同时,Lua程序中可以注册有其他语言实现的函数,这些函数可能由C语言(或其他语言)实现,可以增加一些不容易由Lua实现的功能。这使得Lua是可扩展的。与上面两种观点(Lua作为扩展性语言和可扩展的语言)对应的C和Lua中间有两种交互方式。第一种,C作为应用程序语言,Lua作为一个库使用;第二种,反过来,Lua作为程序语言,C作为库使用。这两种方式,C语言都使用相同的API与Lua通信,因此C和Lua交互这部分称为C API。
C API是一个C代码与Lua进行交互的函数集。他有以下部分组成:读写Lua全局变量的函数,调用Lua函数的函数,运行Lua代码片断的函数,注册C函数然后可以在Lua中被调用的函数,等等。(本书中,术语函数实际上指函数或者宏,API有些函数为了方便以宏的方式实现)
C API遵循C语言的语法形式,这Lua有所不同。当使用C进行程序设计的时候,我们必须注意,类型检查,错误处理,内存分配都很多问题。API中的大部分函数并不检查他们参数的正确性;你需要在调用函数之前负责确保参数是有效的。如果你传递了错误的参数,可能得到 \"segmentation fault\" 这样或者类似的错误信息,而没有很明确的错误信息可以获得。另外,API重点放在了灵活性和简洁性方面,有时候以牺牲方便实用为代价的。一般的任务可能需要涉及很多个API调用,这可能令人烦恼,但是他给你提供了对细节的全部控制的能力,比如错误处理,缓冲大小,和类似的问题。如本章的标题所示,这一章的目标是对当你从C调用Lua时将涉及到哪些内容的预览。如果不能理解某些细节不要着急,后面我们会一一详细介绍。不过,在Lua参考手册中有对指定函数的详细描述。另外,在Lua发布版中你可以看到API的应用的例子,Lua独立的解释器(lua.c)提供了应用代码的例子,而标准库(lmathlib.c、lstrlib.c等等)提供了程序库代码的例子。
从现在开始,你戴上了C程序员的帽子,当我们谈到“你/你们”,我们意思是指当你使用C编程的时候。在C和Lua之间通信关键内容在于一个虚拟的栈。几乎所有的API调用都是对栈上的值进行操作,所有C与Lua之间的数据交换也都通过这个栈来完成。另外,你也可以使用栈来保存临时变量。栈的使用解决了C和Lua之间两个不协调的问题:第一,Lua会自动进行垃圾收集,而C要求显示的分配存储单元,两者引起的矛盾。第二,Lua中的动态类型和C中的静态类型不一致引起的混乱。我们将在24.2节详细地介绍栈的相关内容。