此第一版是为 Lua 5.0 编写的。虽然在很大程度上仍然适用于更高版本,但存在一些差异。
第四版针对 Lua 5.3,可在 亚马逊 和其他书店购买。
购买本书,您还可以帮助支持 Lua 项目


24 – C API 概述

Lua 是一种嵌入式语言。这意味着 Lua 不是一个独立的包,而是一个库,可以与其他应用程序链接,以便将 Lua 功能合并到这些应用程序中。

您可能想知道:如果 Lua 不是一个独立的程序,我们怎么会整本书都在独立使用 Lua?这个谜题的解决方案是 Lua 解释器(可执行文件 lua)。此解释器是一个小应用程序(代码少于五百行),它使用 Lua 库来实现独立解释器。此程序处理与用户的界面,获取其文件和字符串以将它们提供给 Lua 库,而 Lua 库会完成大部分工作(例如实际运行 Lua 代码)。

作为扩展应用程序的库使用的这种能力使 Lua 成为一种扩展语言。同时,使用 Lua 的程序可以在 Lua 环境中注册新函数;此类函数在 C(或其他语言)中实现,并且可以添加无法直接用 Lua 编写的功能。这使 Lua 成为一种可扩展语言

Lua 的这两种视图(作为扩展语言和可扩展语言)对应于 C 和 Lua 之间的两种交互方式。在第一种方式中,C 具有控制权,而 Lua 是库。这种交互方式中的 C 代码就是我们所说的应用程序代码。在第二种方式中,Lua 具有控制权,而 C 是库。在此,C 代码称为库代码。应用程序代码和库代码都使用相同的 API 与 Lua 通信,即所谓的 C API。

C API 是允许 C 代码与 Lua 交互的一组函数。它包含用于读写 Lua 全局变量、调用 Lua 函数、运行 Lua 代码片段、注册 C 函数以便 Lua 代码稍后可以调用它们等等的函数。(在整个文本中,“函数”一词实际上表示“函数或宏”。API 将几个功能实现为宏。)

C API 遵循 C 操作模式,这与 Lua 非常不同。在 C 中编程时,我们必须关心类型检查(和类型错误)、错误恢复、内存分配错误以及其他一些复杂性来源。API 中的大多数函数不会检查其参数的正确性;在调用函数之前,确保参数有效是你的责任。如果你犯了错误,可能会收到“段错误”或类似错误,而不是一个行为良好的错误消息。此外,API 强调灵活性和简单性,有时以易用性为代价。常见任务可能涉及多个 API 调用。这可能很无聊,但它让你可以完全控制所有细节,例如错误处理、缓冲区大小等。

正如其标题所述,本章的目标是在你从 C 中使用 Lua 时概述所涉及的内容。不要费心去理解现在发生的所有细节。稍后,我们会补充细节。不过,不要忘记,你可以在 Lua 参考手册中找到有关特定函数的更多详细信息。此外,你可以在 Lua 发行版本身中找到 API 使用的几个示例。Lua 独立解释器 (lua.c) 提供了应用程序代码的示例,而标准库 (lmathlib.clstrlib.c 等) 提供了库代码的示例。

从现在开始,我们戴上了 C 程序员的帽子。当我们谈论“你”时,我们指的是你在 C 中编程时,或者你被你编写的 C 代码所模拟。

Lua 和 C 之间通信中的一个主要组件是一个无处不在的虚拟堆栈。几乎所有 API 调用都针对此堆栈上的值进行操作。从 Lua 到 C 和从 C 到 Lua 的所有数据交换都通过此堆栈进行。此外,你还可以使用堆栈来保存中间结果。堆栈有助于解决 Lua 和 C 之间的两个阻抗不匹配:第一个是由 Lua 被垃圾回收引起的,而 C 需要显式释放;第二个是由 Lua 中的动态类型与 C 的静态类型之间的冲突引起的。我们将在第 24.2 节中更详细地讨论堆栈。