lua与c相互调用的常用接口

4.6k 词
  <p>lua与c交互主要通过栈,栈底为1,栈顶为-1,以下是其相互调用的常用接口:</p>

栈操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
int (lua_State *L);
返回栈顶元素的索引。 因为索引是从 1 开始编号的, 所以这个结果等于栈上的元素个数; 特别指出,0 表示栈为空。
void lua_settop (lua_State *L, int index);
参数允许传入任何索引以及 0 。 它将把堆栈的栈顶设为这个索引。 如果新的栈顶比原来的大, 超出部分的新元素将被填为 nil 。 如果 index 为 0 , 把栈上所有元素移除。
void lua_pop (lua_State *L, int n);
从栈中弹出 n 个元素。
void lua_insert (lua_State *L, int index);
把栈顶元素移动到指定的有效索引处, 依次移动这个索引之上的元素。 不要用伪索引来调用这个函数, 因为伪索引没有真正指向栈上的位置。
void lua_remove (lua_State *L, int index);
从给定有效索引处移除一个元素, 把这个索引之上的所有元素移下来填补上这个空隙。 不能用伪索引来调用这个函数,因为伪索引并不指向真实的栈上的位置。
void lua_replace (lua_State *L, int index);
把栈顶元素放置到给定位置而不移动其它元素 (因此覆盖了那个位置处的值),然后将栈顶元素弹出。
void lua_pushvalue (lua_State *L, int index);
把栈上给定索引处的元素作一个副本压栈。
void lua_pushboolean (lua_State *L, int b);
把 b 作为一个布尔量压栈。
int lua_toboolean (lua_State *L, int index);
把给定索引处的 Lua 值转换为一个 C 中的布尔量( 0 或是 1 )。 和 Lua 中做的所有测试一样, lua_toboolean 会把任何不同于 false 和 nil 的值当作真返回; 否则就返回假。 (如果你想只接收真正的 boolean 值, 就需要使用 lua_isboolean 来测试值的类型。)
int lua_checkstack (lua_State *L, int n);
确保堆栈上至少有 n 个额外空位。 如果不能把堆栈扩展到相应的尺寸,函数返回假。 失败的原因包括将把栈扩展到比固定最大尺寸还大 (至少是几千个元素)或分配内存失败。 这个函数永远不会缩小堆栈; 如果堆栈已经比需要的大了,那么就保持原样。
lua_Number luaL_checknumber (lua_State *L, int arg);
检查函数的第 arg 个参数是否是一个 数字,并返回这个数字。
int lua_getglobal (lua_State *L, const char *name);
把全局变量 name 里的值压栈,返回该值的类型。
void lua_setglobal (lua_State *L, const char *name);
从堆栈上弹出一个值,并将其设为全局变量 name 的新值。

table操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
void lua_createtable (lua_State *L, int narr, int nrec);
创建一张新的空表压栈。 参数 narr 建议了这张表作为序列使用时会有多少个元素; 参数 nrec 建议了这张表可能拥有多少序列之外的元素。 Lua 会使用这些建议来预分配这张新表。 如果你知道这张表用途的更多信息,预分配可以提高性能。 否则,你可以使用函数 lua_newtable 。
void lua_newtable (lua_State *L);
创建一张空表,并将其压栈。 它等价于 lua_createtable(L, 0, 0) 。
int lua_gettable (lua_State *L, int index);
把 t[k] 的值压栈, 这里的 t 是指索引指向的值, 而 k 则是栈顶放的值。
这个函数会弹出堆栈上的键,把结果放在栈上相同位置。 和在 Lua 中一样, 这个函数可能触发对应 "index" 事件的元方法 (参见 §2.4 )。
返回压入值的类型。
int lua_getfield (lua_State *L, int index, const char *k); // = lua_pushstring(L, key); lua_gettable(L, -2);
把 t[k] 的值压栈, 这里的 t 是索引指向的值。 在 Lua 中,这个函数可能触发对应 "index" 事件对应的元方法 (参见 §2.4 )。
函数将返回压入值的类型。
void lua_settable (lua_State *L, int index);
做一个等价于 t[k] = v 的操作, 这里 t 是给出的索引处的值, v 是栈顶的那个值, k 是栈顶之下的值。
这个函数会将键和值都弹出栈。 跟在 Lua 中一样,这个函数可能触发一个 "newindex" 事件的元方法 (参见 §2.4)。
void lua_setfield (lua_State *L, int index, const char *k);
做一个等价于 t[k] = v 的操作, 这里 t 是给出的索引处的值, 而 v 是栈顶的那个值。
这个函数将把这个值弹出栈。 跟在 Lua 中一样,这个函数可能触发一个 "newindex" 事件的元方法 (参见 §2.4)。
int lua_rawget (lua_State *L, int index);
类似于 lua_gettable , 但是作一次直接访问(不触发元方法)。
int lua_rawgeti (lua_State *L, int index, lua_Integer n);
把 t[n] 的值压栈, 这里的 t 是指给定索引处的表。 这是一次直接访问;就是说,它不会触发元方法。
void lua_rawset (lua_State *L, int index);
类似于 lua_settable , 但是是做一次直接赋值(不触发元方法)。
void lua_rawseti (lua_State *L, int index, lua_Integer i);
等价于 t[i] = v , 这里的 t 是指给定索引处的表, 而 v 是栈顶的值。
这个函数会将值弹出栈。 赋值是直接的;即不会触发元方法。
int lua_getmetatable (lua_State *L, int index);
如果该索引处的值有元表,则将其元表压栈,返回 1 。 否则不会将任何东西入栈,返回 0

调lua函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
int lua_pcall (lua_State *L, int nargs, int nresults, int msgh);
以保护模式调用一个函数。
nargs 和 nresults 的含义与 lua_call 中的相同。 如果在调用过程中没有发生错误, lua_pcall 的行为和 lua_call 完全一致。 但是,如果有错误发生的话, lua_pcall 会捕获它, 然后把唯一的值(错误消息)压栈,然后返回错误码。 同 lua_call 一样, lua_pcall 总是把函数本身和它的参数从栈上移除。
如果 msgh 是 0 , 返回在栈顶的错误消息就和原始错误消息完全一致。 否则, msgh 就被当成是 错误处理函数 在栈上的索引位置。 (在当前的实现里,这个索引不能是伪索引。) 在发生运行时错误时, 这个函数会被调用而参数就是错误消息。 错误处理函数的返回值将被 lua_pcall 作为错误消息返回在堆栈上。
典型的用法中,错误处理函数被用来给错误消息加上更多的调试信息, 比如栈跟踪信息。 这些信息在 lua_pcall 返回后, 由于栈已经展开,所以收集不到了。
lua_pcall 函数会返回下列常数 (定义在 lua.h 内)中的一个:
LUA_OK (0): 成功。
LUA_ERRRUN: 运行时错误。
LUA_ERRMEM: 内存分配错误。对于这种错,Lua 不会调用错误处理函数。
LUA_ERRERR: 在运行错误处理函数时发生的错误。
LUA_ERRGCMM: 在运行 __gc 元方法时发生的错误。 (这个错误和被调用的函数无关。)
int lua_pcallk (lua_State *L,
int nargs,
int nresults,
int msgh,
lua_KContext ctx,
lua_KFunction k);
这个函数的行为和 lua_pcall 完全一致,只不过它还允许被调用的函数让出

lua调c

注册c函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
typedef int (*lua_CFunction) (lua_State *L); //每个函数有自己的局部私有栈
C 函数的类型。
为了正确的和 Lua 通讯, C 函数必须使用下列协议。 这个协议定义了参数以及返回值传递方法: C 函数通过 Lua 中的栈来接受参数, 参数以正序入栈(第一个参数首先入栈)。 因此,当函数开始的时候, lua_gettop(L) 可以返回函数收到的参数个数。 第一个参数(如果有的话)在索引 1 的地方, 而最后一个参数在索引 lua_gettop(L) 处。 当需要向 Lua 返回值的时候, C 函数只需要把它们以正序压到堆栈上(第一个返回值最先压入), 然后返回这些返回值的个数。 在这些返回值之下的,堆栈上的东西都会被 Lua 丢掉。 和 Lua 函数一样,从 Lua 中调用 C 函数也可以有很多返回值。
void lua_pushcfunction (lua_State *L, lua_CFunction f); : //注册c函数 lua_pushcfunction(L, I_sin); lua_setglobal(L, "mysin");
将一个 C 函数压栈。 这个函数接收一个 C 函数指针, 并将一个类型为 function 的 Lua 值压栈。 当这个栈顶的值被调用时,将触发对应的 C 函数。
注册到 Lua 中的任何函数都必须遵循正确的协议来接收参数和返回值 (参见 lua_CFunction )。
lua_pushcfunction 是作为一个宏定义出现的:
void lua_register (lua_State *L, const char *name, lua_CFunction f); //注册c函数
把 C 函数 f 设到全局变量 name 中。 它通过一个宏定义:
(lua_pushcfunction(L, f), lua_setglobal(L, n))
typedef struct luaL_Reg {
const char *name;
lua_CFunction func;
} luaL_Reg;
用于 luaL_setfuncs 注册函数的数组类型。 name 指函数名,func 是函数指针。 任何 luaL_Reg 数组必须以一对 name 与 func 皆为 NULL 结束。

c模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//in c
static int I_dir (lua_State *L) {
//
}
static const struct luaL_Reg mylib[] = {
{"dir", I_dir},
{NULL, NULL} //结尾
}
int luaopen_mylib (lua_State *L) {
luaL_register(L, "mylib", mylib);
return 1
}
// in lua
require "mylib"

参考

http://cloudwu.github.io/lua53doc/manual.html