第一版是为 Lua 5.0 编写的。虽然在很大程度上仍然适用于更高版本,但有一些区别。
第四版针对 Lua 5.3,可以在 Amazon 和其他书店买到。
购买本书,您还可以帮助支持 Lua 项目。
用 Lua 编程 | ||
第四部分。C API 第 25 章。扩展您的应用程序 |
作为一个更高级的示例,我们将构建一个用于调用 Lua 函数的包装器,使用 C 中的 vararg
工具。我们的包装器函数(我们称之为 call_va
)接收要调用的函数的名称、描述参数和结果类型的字符串、然后是参数列表,最后是用于存储结果的变量指针列表;它处理 API 的所有详细信息。使用此函数,我们可以简单地将我们之前的示例编写为
call_va("f", "dd>d", x, y, &z);其中字符串
"dd>d"
表示“两个 double 类型的参数,一个 double 类型的结果”。此描述符可以使用字母 `d
´ 表示 double,`i
´ 表示整数,`s
´ 表示字符串;`>
´ 将参数与结果分隔开。如果函数没有结果,则 `>
´ 是可选的。
#include <stdarg.h> void call_va (const char *func, const char *sig, ...) { va_list vl; int narg, nres; /* number of arguments and results */ va_start(vl, sig); lua_getglobal(L, func); /* get function */ /* push arguments */ narg = 0; while (*sig) { /* push arguments */ switch (*sig++) { case 'd': /* double argument */ lua_pushnumber(L, va_arg(vl, double)); break; case 'i': /* int argument */ lua_pushnumber(L, va_arg(vl, int)); break; case 's': /* string argument */ lua_pushstring(L, va_arg(vl, char *)); break; case '>': goto endwhile; default: error(L, "invalid option (%c)", *(sig - 1)); } narg++; luaL_checkstack(L, 1, "too many arguments"); } endwhile: /* do the call */ nres = strlen(sig); /* number of expected results */ if (lua_pcall(L, narg, nres, 0) != 0) /* do the call */ error(L, "error running function `%s': %s", func, lua_tostring(L, -1)); /* retrieve results */ nres = -nres; /* stack index of first result */ while (*sig) { /* get results */ switch (*sig++) { case 'd': /* double result */ if (!lua_isnumber(L, nres)) error(L, "wrong result type"); *va_arg(vl, double *) = lua_tonumber(L, nres); break; case 'i': /* int result */ if (!lua_isnumber(L, nres)) error(L, "wrong result type"); *va_arg(vl, int *) = (int)lua_tonumber(L, nres); break; case 's': /* string result */ if (!lua_isstring(L, nres)) error(L, "wrong result type"); *va_arg(vl, const char **) = lua_tostring(L, nres); break; default: error(L, "invalid option (%c)", *(sig - 1)); } nres++; } va_end(vl); }尽管具有通用性,但此函数遵循我们之前示例中的相同步骤:它推送函数,推送参数,执行调用,并获取结果。它的大部分代码都很直接,但有一些细微差别。首先,它不需要检查
func
是否是一个函数;lua_pcall
将触发任何偶发错误。其次,因为它推送任意数量的参数,所以它必须检查堆栈空间。第三,因为函数可能会返回字符串,所以 call_va
无法从堆栈中弹出结果。在完成使用偶发字符串结果(或将其复制到其他缓冲区)后,由调用者弹出它们。
版权所有 © 2003–2004 Roberto Ierusalimschy。保留所有权利。 |