博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
0基础lua学习(十八)C调用Lua----02Lua堆栈
阅读量:5117 次
发布时间:2019-06-13

本文共 4548 字,大约阅读时间需要 15 分钟。

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》,内容过多,适当进行了删减 ,加入自己的理解。

转载于:https://www.cnblogs.com/hiwoshixiaoyu/p/10034970.html

你可能感兴趣的文章
C# Json 序列化大全--任我行
查看>>
BULK INSERT如何将大量数据高效地导入SQL Server
查看>>
caioj1421&&hdu2167: [视频]【状态压缩】选数
查看>>
使用Solr构建企业级的全文检索(一)---------开篇
查看>>
(转)贡献15本pdf完整版经典Android教程和海量Android源码
查看>>
day05
查看>>
nginx源码学习_数据结构(ngx_str_t)
查看>>
Ubuntu 14.04远程登录服务器--ssh的安装和配置 ( 使用secureCRT需要的ssh支持 )
查看>>
【转】GPS基线解算模式
查看>>
快速排序实现代码 算法导论7.1 7.2 7.4
查看>>
C#给图片加文字和图片的水印
查看>>
JDK1.8 之Lambda
查看>>
如何给a标签绑定ajax事件
查看>>
花瓣网图片爬取
查看>>
网络营销相关缩写名称CPM CPT CPC CPA CPS SEM SEO解析
查看>>
微信、陌陌阴影下,中国社交领域未来的机会在哪里,四个象限看社交的格局...
查看>>
go语言,golang学习笔记1 官网下载安装,中文社区,开发工具LiteIDE
查看>>
Python开发WebService:REST,web.py,eurasia,Django
查看>>
图像处理——图像增强
查看>>
hdu 2051
查看>>