• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

0基础lua学习(十八)C调用Lua----02Lua堆栈

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

1. Lua与C通信,为什么使用虚拟的一个堆栈?

     当在 Lua 和 C 之间交换数据有两个问题:

  • 动态与静态类型系统的不匹配
  • 自动与手动内存管理的不一致

Lua中a[k]=vak可能的类型,有很多种,我们要想映射这个变量可能要写三个参数类型的每一种组合函数。(表、数字、字符串)

Cunion 类型能来解决这个问题吗?

如此复杂的类型映射到其它语言可能很困难,

  •  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, 但是字符串中间也可能包
0lua_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人参与评论

请发表评论

全部评论

专题导读
上一篇:
RT1502移植LUA成功的总结发布时间:2022-07-22
下一篇:
tengine安装ngx_http_lua_module发布时间:2022-07-22
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap