此第一版是为 Lua 5.0 编写的。虽然在很大程度上仍然与更高版本相关,但有一些差异。
第四版针对 Lua 5.3,可在 亚马逊 和其他书店购买。
购买本书,您还可以帮助 支持 Lua 项目。
用 Lua 编程 | ||
第四部分。C API 第 26 章。从 Lua 调用 C |
Lua 库是一个定义多个 Lua 函数并将它们存储在适当位置(通常作为表中的条目)的块。Lua 的 C 库模仿此行为。除了定义其 C 函数之外,它还必须定义一个特殊函数,该函数对应于 Lua 库的主块。一旦调用,此函数将注册库的所有 C 函数并将它们存储在适当的位置。与 Lua 主块一样,它还会初始化库中需要初始化的其他任何内容。
Lua 通过此注册过程“看到”C 函数。一旦 C 函数在 Lua 中表示和存储,Lua 程序就会通过直接引用其地址(这是我们在注册函数时提供给 Lua 的)来调用它。换句话说,一旦注册,Lua 就不依赖于函数名称、包位置或可见性规则来调用函数。通常,C 库只有一个公共(extern)函数,即打开库的函数。所有其他函数都可以是私有的,在 C 中声明为 static
。
当您使用 C 函数扩展 Lua 时,即使您只想注册一个 C 函数,最好将您的代码设计为 C 库:迟早(通常是早)您将需要其他函数。与往常一样,辅助库为此任务提供了一个帮助器函数。luaL_openlib
函数接收一个 C 函数及其各自名称的列表,并将它们全部注册到具有库名称的表中。例如,假设我们想要创建一个包含我们之前定义的 l_dir
函数的库。首先,我们必须定义库函数
static int l_dir (lua_State *L) { ... /* as before */ }接下来,我们声明一个包含所有函数及其各自名称的数组。此数组具有类型为
luaL_reg
的元素,这是一个具有两个字段的结构:一个字符串和一个函数指针。
static const struct luaL_reg mylib [] = { {"dir", l_dir}, {NULL, NULL} /* sentinel */ };在我们的示例中,只有一个要声明的函数(
l_dir
)。请注意,数组中的最后一对必须是 {NULL, NULL}
,以表示其结束。最后,我们使用 luaL_openlib
声明一个主函数
int luaopen_mylib (lua_State *L) { luaL_openlib(L, "mylib", mylib, 0); return 1; }
luaL_openlib
的第二个参数是库名。此函数创建(或重新使用)一个具有给定名称的表,并用数组 mylib
指定的名称-函数对填充该表。luaL_openlib
函数还允许我们为库中的所有函数注册通用上值。现在,我们不使用上值,因此调用中的最后一个参数为零。返回时,luaL_openlib
将打开库的表保留在堆栈中。luaopen_mylib
函数返回 1 以将此值返回给 Lua。(与 Lua 库一样,此返回是可选的,因为该库已分配给全局变量。同样,与 Lua 库一样,它没有任何成本,并且偶尔可能有用。)
完成库后,我们必须将其链接到解释器。如果 Lua 解释器支持此功能,最方便的方法是使用动态链接功能。(请记住 第 8.2 节 中关于动态链接的讨论。)在这种情况下,您必须使用代码创建一个动态库(Windows 中的 .dll
文件,Linux 中的 .so
文件)。之后,您可以使用 loadlib
直接从 Lua 中加载库。调用
mylib = loadlib("fullname-of-your-library", "luaopen_mylib")将
luaopen_mylib
函数转换为 Lua 中的 C 函数,并将此函数分配给 mylib
。(这就解释了为什么 luaopen_mylib
必须与任何其他 C 函数具有相同的原型。)接下来,调用 mylib()
运行 luaopen_mylib
,打开库。
如果您的解释器不支持动态链接,那么您必须使用新库重新编译 Lua。除此之外,您需要某种方法来告诉独立解释器,当它打开一个新状态时,它应该打开此库。一些宏可以简化此任务。首先,您必须创建一个头文件(我们称之为 mylib.h
),其内容如下
int luaopen_mylib (lua_State *L); #define LUA_EXTRALIBS { "mylib", luaopen_mylib },第一行声明打开函数。下一行将宏
LUA_EXTRALIBS
定义为解释器在创建新状态时调用的函数数组中的一个新条目。(此数组的类型为 struct luaL_reg[]
,因此我们需要在那里放置一个名称。)
要在解释器中包含此头文件,您可以在编译器选项中定义宏 LUA_USERCONFIG
。对于命令行编译器,您通常必须添加类似以下的选项
-DLUA_USERCONFIG=\"mylib.h\"(反斜杠保护 shell 中的引号;当我们指定包含文件名时,C 中需要这些引号。)在集成开发环境中,您必须在项目设置中添加类似的内容。然后,当您重新编译
lua.c
时,它将包含 mylib.h
,因此在要打开的库列表中使用 LUA_EXTRALIBS
的新定义。
版权所有 © 2003–2004 Roberto Ierusalimschy。保留所有权利。 |