0基础lua学习(十八)C调用Lua----02Lua堆栈
2017-11-13 14:51
260 查看
1. Lua与C通信,为什么使用虚拟的一个堆栈?
当在 Lua 和 C 之间交换数据有两个问题:动态与静态类型系统的不匹配
自动与手动内存管理的不一致
Lua中a[k]=v,a和k可能的类型,有很多种,我们要想映射这个变量可能要写三个参数类型的每一种组合函数。(表、数字、字符串)
C中union
类型能来解决这个问题吗?
如此复杂的类型映射到其它语言可能很困难,
Lua 不仅被设计为与
C/C++易于交互,
Java,Fortran 以及类似的语言也一样。
Lua负责垃圾回收:如果我们将 Lua 值保存在 C 变量中, Lua 引擎没有办法了解这种用法;它可能错误地认为某个值为垃圾并收集他。
所以,不能使用union关键字
替代的方案:
它用一个抽象的栈在 Lua 与 C 之间交换值。栈中的每一条记录都可以保存任何 Lua 值。
2.获取参数的过程:
无论你何时想要从 Lua 请求一个值(比如一个全局变量的值),调用 Lua,被请求的值将会被压入栈。无论你何时想要传递一个值给 Lua,首先将这个值压入栈,然后调用 Lua(这个值将被弹出)。 我们仍然需要一个不同的函数将每种 C 类型压入栈和一个不同函数从栈上取值(注:只是取出不是弹出),但是我们避免了多种不同类型参数的函数组合。另外,因为栈是由 Lua 来管理的,垃圾回收器知道那个值正在被 C 使用。 几乎所有的 API函数都用到了栈。
3.Lua栈的规则:
Lua 以一个严格的 LIFO 规则(后进先出;也就是说,始终存取栈顶)来操作栈。当你调用 Lua 时,它只会改变栈顶部分。你的C代码却有更多的自由;更明确的来讲,你可以查询栈上的任何元素,甚至是在任何一个位置插入和删除元素
4.压入元素
void lua_pushnil (lua_State *L); void lua_pushboolean (lua_State *L, int bool); void lua_pushnumber (lua_State *L, double n); void lua_pushlstring (lua_State *L, const char *s,size_t length); //任意的字符串(char*类型,允许包含'\0'字符)用 lua_pushlstring, //C语言风格(以'\0'结束)的字符串( const char*)用 lua_pushstring: void lua_pushstring (lua_State *L, const char *s);
Lua 中的字符串不是以零为结束符的;它们依赖于一个明确的长度,因此可以包含
任意的二进制数据。将字符串压入串的正式函数是lua_pushlstring,它要求一个明确的长度作为参数。
对于以零结束的字符串,你可以用lua_pushstring(它用
strlen 来计算字符串长度)。
Lua 从来不保持一个指向外部字符串(或任何其它对象,除了
C 函数——它总
是静态指针)的指针。
对于它保持的所有字符串,Lua
要么做一份内部的拷贝要么重新利用已经存在的字符串。因此,一旦这些函数返回之后你可以自由的修改或是释放你的缓冲区。
5.查询元素
API 用索引来访问栈中的元素。在栈中的第一个元素(也就是第一个被压入栈的)有索引 1,下一个有索引2,以此类推。
我们也可以用栈顶作为参照来存取元素,利用负索引。在这种情况下,-1
指出栈顶元素(也就是最后被压入的),-2
指出它的前一个元素,以此类推。
LUA_API int (lua_isnumber)(lua_State *L,int idx); LUA_API int (lua_isstring)(lua_State *L,int idx); LUA_API int (lua_iscfunction)(lua_State *L,int idx); LUA_API int (lua_isuserdata)(lua_State *L,int idx); int lua_is... (lua_State *L, int index); //获取值 int lua_toboolean (lua_State *L, int index); double lua_tonumber (lua_State *L, int index); const char * lua_tostring (lua_State *L, int index); size_t lua_strlen (lua_State *L, int index);
Lua_tostring 函数返回一个指向字符串的内部拷贝的指针。你不能修改它(使你想起
那里有一个 const)。只要这个指针对应的值还在栈内,
Lua 会保证这个指针一直有效。
当一个 C 函数返回后, Lua 会清理他的栈,所以,有一个原则:永远不要将指向 Lua 字符串的指针保存到访问他们的外部函数中。
Lua_string 返回的字符串结尾总会有一个字符结束标志
0, 但是字符串中间也可能包
含 0,lua_strlen
返回字符串的实际长度。特殊情况下,假定栈顶的值是一个字符串,下
面的断言(assert)总是有效的:
const char *s = lua_tostring(L, -1); /* any Lua string */ size_t l = lua_strlen(L, -1); /*its length */ assert(s[l] == '\0'); assert(strlen(s) <= l);
6.其他堆栈操作
除开上面所提及的 C 与堆栈交换值的函数外, API 也提供了下列函数来完成通常的堆栈维护工作://函数 lua_gettop 返回堆栈中的元素个数,它也是栈顶元素的索引。注意一个负数//索引-x 对应于正数索引 gettop-x+1。 int lua_gettop(lua_State *L); //lua_settop设置栈顶(也就是堆栈中的元素个数)为一个指定的值。如果开始的栈顶高于新的栈顶,顶部的值被丢弃。否则,为了得到指定的大小这个函数压入相应个数的空值//(nil)到栈上。特别的, lua_settop(L,0)清空堆栈。你也可以用负数索引作为调用 lua_settop 的参数;那将会设置栈顶到指定的索引。 //利用这种技巧, API 提供了下面这个宏,它从堆栈中弹出 n 个元素: //#definelua_pop(L,n) lua_settop(L, -(n)-1) void lua_settop(lua_State *L, int index); //函数 lua_pushvalue 压入堆栈上指定索引的一个抟贝到栈顶; lua_remove 移除指定索引位置的元素,并将其上面所有的元素下移来填补这个位置的空白; void lua_pushvalue(lua_State *L, int index); void lua_remove(lua_State *L, int index); void lua_insert(lua_State *L, int index); void lua_replace(lua_State *L, int index);
lua_insert移动栈顶元素到指定索引的位置,并将这个索引位置上面的元素全部上移至栈顶被移动留下的空隔;最后,lua_replace从栈顶弹出元素值并将其设置到指定索引位置,没有任何移动操作。
注意到下面的操作对堆栈没有任何影响:
lua_settop(L, -1); /* set top to its current value */ lua_insert(L, -1); /* move top element to the top */
demo:
static void stackDump (lua_State *L) { int i; int top = lua_gettop(L); //从栈底到栈顶遍历了整个堆栈,依照每个元素自己的类型打印出其值。 for (i = 1; i <= top; i++) { /* repeat for each level */ int t = lua_type(L, i); switch (t) { case LUA_TSTRING: /* strings */ printf("`%s'", lua_tostring(L, i)); break; case LUA_TBOOLEAN: /* booleans */ printf(lua_toboolean(L, i) ? "true" : "false"); break; case LUA_TNUMBER: /* numbers */ printf("%g", lua_tonumber(L, i)); break; default: /* other values */ printf("%s", lua_typename(L, t)); break; } printf(" "); /* put a separator */ } printf("\n"); /* end the listing */ } int _tmain(int argc, _TCHAR* argv[]) lua_State *L = lua_open(); lua_pushboolean(L, 1); lua_pushnumber(L, 10); lua_pushnil(L); lua_pushstring(L, "hello"); stackDump(L); /* true 10 nil `hello' */ lua_pushvalue(L, -4); stackDump(L); /* true 10 nil `hello' true */ lua_replace(L, 3); stackDump(L); /* true 10 true `hello' */ lua_settop(L, 6); stackDump(L); /* true 10 true `hello' nil nil */ lua_remove(L, -3); stackDump(L); /* true 10 true nil nil */ lua_settop(L, -5); stackDump(L); /* true */ lua_close(L); return 0; }
摘自 《Programming in Lua》,内容过多,适当进行了删减 ,加入自己的理解。
相关文章推荐
- 0基础lua学习(十九)C调用Lua----03C调用lua 函数和变量
- 0基础lua学习(十七)C调用Lua----01小demo
- lua学习02——还是基础
- lua学习01——基础
- Lua基础教程之表(Table)学习笔记
- 黑马程序员_学习日记6_C#基础归纳总结之堆栈分配图解
- 前端开发学习笔记02----HTML基础
- 【零基础学习iOS开发】【02-C语言】08-基本运算
- 李洪强iOS开发之【零基础学习iOS开发】【02-C语言】07-基本数据类型
- oracle 基础学习 02---- %type | %rowtype | record | merge into | insert all | insert first
- 端口02 - 零基础入门学习汇编语言68
- 【零基础学习iOS开发】【02-C语言】05-进制
- 关于数组的认识02 - 零基础入门学习Delphi16
- java基础学习02(简单的java程序)
- 函数调用 堆栈 分类: 嵌入式开发学习 2011-04-08 23:56 4110人阅读 评论(0) 收藏
- lua基础学习 - 闭合函数(closure)
- 数据处理的两个基本问题02 - 零基础入门学习汇编语言39
- Python学习笔记:02 基础:变量、整数、字符串、赋值、基本输出、注释、代码块
- DLL技术应用02 - 零基础入门学习Delphi45
- 0基础lua学习(九)数组