lua学习24:《Lua程序设计(第2版)》第24章
来源:互联网 发布:linux系统自带rpm在哪 编辑:程序博客网 时间:2024/06/05 18:11
这个问题的答案在于Lua解释器(可执行的lua)。
Lua解释器是一个使用Lua标准库实现的独立的解释器。解释器负责程序和使用者的接口:从使用者那里获取文件或者字符串,并传给Lua标准库,Lua标准库负责最终的代码运行。就因为这个特性,所以Lua可以多平台下运行。2、Lua是一种扩展性语言。有两种扩展方式:
第一种,C作为应用程序语言,Lua作为一个库使用,C语言拥有控制权;
第二种,反过来,Lua作为程序语言,C作为库使用,Lua拥有控制权。
这两种方式,C语言都使用相同的API与Lua通信,因此C和Lua交互这部分称为C API。
3、在C和Lua之间通信关键内容在于一个虚拟的栈。
几乎所有的API调用都是对栈上的值进行操作,所有C与Lua之间的数据交换也都通过这个栈来完成。另外,你也可以使用栈来保存临时变量。
栈的使用解决了C和Lua之间两个不协调的问题:
第一,Lua会自动进行垃圾收集,而C要求显示的分配存储单元,两者引起的矛盾。
第二,Lua中的动态类型和C中的静态类型不一致引起的混乱。
4、第一个示例程序:
#ifdef __cplusplusextern "C" {#include "lua.h"#include <lauxlib.h> #include <lualib.h> } #else#include <lua.h>#include <lualib.h>#include <lauxlib.h>#endifint main (void){ char buff[256];int error;lua_State *L = luaL_newstate(); //打开 Lua ,创建一个新环境,以前的版本用lua_openlua_openlibs(L); //打开标准库,也可以分别单独打开luaopen_base(L);luaopen_table(L)等while (fgets(buff, sizeof(buff), stdin) != NULL) //从标准输入读取buff{error = luaL_loadbuffer(L, buff, strlen(buff),"line") //将buff里内容压入栈|| lua_pcall(L, 0, 0, 0); //运行栈中内容,运行完后所有的参数以及函数本身都会出栈//lua_loadbuffer出错时将会把错误信息压入栈中if (error){fprintf(stderr, "%s", lua_tostring(L, -1)); //将栈顶的错误信息转换成字符串并输出到标准错误流lua_pop(L, 1); //从栈中弹出错误消息 ,这里第二个参数用-1也行,因为此时栈中只有一个元素}}lua_close(L);return 0;}
采用extern "C" {} 这种形式的声明,可以使得CPP 与C 之间的接口具有互通性,不会由于语言内部的机制导致连接目标文件的时候出现错误。Lua语言是C语言编写的,C++中编译的时候需要加上extern "C" {} 这种形式的声明。如果想深入了解请访问http://blog.csdn.net/kingking27/article/details/39056085
stderr与stdout区别:
stderr 总是直接输出到屏幕,不需要回车刷新缓冲区就直接输出
stdout 需要回车刷新缓冲区输出,可以重定向到其他输出设备
头文件lua.h 定义了Lua提供的基础函数,其中包括创建一个新的Lua环境的函数(如lua_newstate),调用Lua函数(如lua_pcall)的函数,读取/写入Lua环境的全局变量的函数,注册可以被Lua代码调用的新函数的函数,等等。所有在lua.h中被定义的都有一个lua_前缀。
lauxlib.h 定义了辅助库(auxlib)提供的函数。同样,所有在其中定义的函数等都以luaL_打头(例如,luaL_loadbuffer)。辅助库利用lua.h中提供的基础函数提供了更高层次上的抽象。
lualib.h 定义了打开库的函数。
5、Lua和C之间是通过一个虚拟栈进行数据交互的,栈中的每一条记录都可以保存任何Lua值。无论你何时想要从Lua请求一个值(比如一个全局变量的值),调用Lua,被请求的值将会被压入栈。无论你何时想要传递一个值给Lua,首先将这个值压入栈,然后调用Lua(这个值将被弹出)。Lua以一个严格的LIFO规则(后进先出;也就是说,始终存取栈顶)来操作栈。当你调用Lua时,它只会改变栈顶部分。
6、压入元素
void lua_pushnil(lua_State* L); --nil值
void lua_pushboolean(lua_State* L, int b); --布尔值
void lua_pushnumber(lua_State* L, lua_Number n); --浮点数
void lua_pushinteger(lua_State* L, lua_Integer n); --整型
void lua_pushlstring(lua_State* L, const char* s, size_t len); --指定长度的内存数据
void lua_pushstring(lua_State* L, const char* s); --以零结尾的字符串,其长度可由strlen得出。
对于字符串数据,Lua不会持有他们的指针,而是调用在API时生成一个内部副本,因此,即使在这些函数返回后立刻释放或修改这些字符串指针,也不会有任何问题。
在向栈中压入数据时,可以通过调用下面的函数判断是否有足够的栈空间可用,一般而言,Lua会预留20个槽位,对于普通应用来说已经足够了,除非是遇到有很多参数的函数。
int lua_checkstack(lua_State* L, int extra) --期望得到extra数量的空闲槽位,如果不能扩展并获得,返回false。
7、 查询元素
API使用“索引”来引用栈中的元素,第一个压入栈的为1,第二个为2,依此类推。我们也可以使用负数作为索引值,其中-1表示为栈顶元素,-2为栈顶下面的元素,同样依此类推。Lua提供了一组特定的函数用于检查返回元素的类型,如:
int lua_isboolean (lua_State *L, int index);
int lua_iscfunction (lua_State *L, int index);
int lua_isfunction (lua_State *L, int index);
int lua_isnil (lua_State *L, int index);
int lua_islightuserdata (lua_State *L, int index);
int lua_isnumber (lua_State *L, int index);
int lua_isstring (lua_State *L, int index);
int lua_istable (lua_State *L, int index);
int lua_isuserdata (lua_State *L, int index);
以上函数,成功返回1,否则返回0。需要特别指出的是,对于lua_isnumber而言,不会检查值是否为数字类型,而是检查值是否能转换为数字类型。
Lua还提供了一个函数lua_type,用于获取元素的类型,函数原型如下:
int lua_type (lua_State *L, int index);
该函数的返回值为一组常量值,分别是:LUA_TNIL、LUA_TNUMBER、LUA_TBOOLEAN、LUA_TSTRING、LUA_TTABLE、LUA_TFUNCTION、LUA_TUSERDATA、LUA_TTHREAD和LUA_TLIGHTUSERDATA。这些常量通常用于switch语句中。
8、转换元素
除了上述函数之外,Lua还提供了一组转换函数,如:
int lua_toboolean (lua_State *L, int index);
lua_CFunction lua_tocfunction (lua_State *L, int index);
lua_Integer lua_tointeger (lua_State *L, int index);
const char *lua_tolstring (lua_State *L, int index, size_t *len);
lua_Number lua_tonumber (lua_State *L, int index);
const void *lua_topointer (lua_State *L, int index);
const char *lua_tostring (lua_State *L, int index);
void *lua_touserdata (lua_State *L, int index);
--string类型返回字符串长度,table类型返回操作符'#'等同的结果,userdata类型返回分配的内存块长度。
size_t lua_objlen (lua_State *L, int index);
对于上述函数,如果调用失败,lua_toboolean、lua_tonumber、lua_tointeger和lua_objlen均返回0,而其他函数则返回NULL。在很多时候0不是一个很有效的用于判断错误的值,但是ANSI C没有提供其他可以表示错误的值。因此对于这些函数,在有些情况下需要先使用lua_is*系列函数判断是否类型正确,而对于剩下的函数,则可以直接通过判断返回值是否为NULL即可。
对于lua_tolstring函数返回的指向内部字符串的指针,在该索引指向的元素被弹出之后,将无法保证仍然有效。该函数返回的字符串末尾均会有一个尾部0。如果不需要长度信息,可以将第三个参数设为NULL来调用lua_tolstring。
lua_objien函数可以返回一个对象的“长度”。对于字符串和table,这个值是长度操作符"#"的结果。这个函数还可以用于获取一个“完全userdata(full userdata)”的大小。
9、打印整个栈内容的函数
static void stackDump(lua_State* L) { int top = lua_gettop(L);//获取栈的元素个数 for (int i = 1; i <= top; ++i) { int t = lua_type(L,i);//获取对应索引i的元素类型 switch(t) { case LUA_TSTRING: printf("'%s'",lua_tostring(L,i)); break; case LUA_TBOOLEAN: printf(lua_toboolean(L,i) ? "true" : "false"); break; case LUA_TNUMBER: printf("%g",lua_tonumber(L,i)); break; default://其他值打印类型名 printf("%s",lua_typename(L,t)); break; } printf(" ");//打印一个分隔符 } printf("\n");}
10、除了上面给出的数据交换函数之外,Lua的C API还提供了一组用于操作虚拟栈的普通函数,如:
int lua_gettop(lua_State* L); --返回栈中元素的个数。
void lua_settop(lua_State* L, int index); --将栈顶设置为指定的索引值。
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还提供了一个宏用于弹出指定数量的元素:#define lua_pop(L,n) lua_settop(L, -(n) - 1)
- int main()
- {
- lua_State* L = luaL_newstate();
- 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;
- }
1). C程序调用Lua代码的错误处理:
通常情况下,应用程序代码是以“无保护”模式运行的。因此,当Lua发现“内存不足”这类错误时,只能通过调用“紧急”函数来通知C语言程序,之后在结束应用程序。用户可通过lua_atpanic来设置自己的“紧急”函数。如果希望应用程序代码在发生Lua错误时不会退出,可通过调用lua_pcall函数以保护模式运行Lua代码。这样再发生内存错误时,lua_pcall会返回一个错误代码,并将解释器重置为一致的状态。如果要保护与Lua的C代码,可以使用lua_cpall函数,它将接受一个C函数作为参数,然后调用这个C函数。
2). Lua调用C程序:
通常而言,当一个被Lua调用的C函数检测到错误时,它就应该调用lua_error,该函数会清理Lua中所有需要清理的资源,然后跳转回发起执行的那个lua_pcall,并附上一条错误信息。
- lua学习24:《Lua程序设计(第2版)》第24章
- lua学习2:《Lua程序设计(第2版)》第2章
- lua学习1:《Lua程序设计(第2版)》第1章
- lua学习25:《Lua程序设计(第2版)》第25章
- lua学习26:《Lua程序设计(第2版)》第26章
- 《Lua程序设计[第二版]》第1,2章笔记
- Lua程序设计(第2版)第二章学习随笔——类型和值
- Lua程序设计(第2版)第三章学习随笔——表达式
- Lua程序设计(第2版)第四章学习随笔——语句
- Lua程序设计(第2版)第五章学习随笔——函数
- Lua程序设计(第2版)第六章学习随笔——深入函数
- Lua程序设计:第1章 开始
- Lua程序设计:第3章 表达式
- Lua程序设计:第4章 语句
- Lua程序设计:第5章 函数
- Lua程序设计:第6章 深入函数
- 《Lua程序设计[第二版]》第3,4章笔记
- 《Lua程序设计[第二版]》第5,6章笔记
- 一口一口吃掉Struts(一)——用JSP+Servlet演示Struts的基本原理
- Android 编辑框(EditText)属性学习
- Struts2返回JSON数据的具体应用范例
- 数据结构学习18——排序的综述
- ArcGIS教程:网络元素
- lua学习24:《Lua程序设计(第2版)》第24章
- AC自动机zoj3228
- Kettle学习之Truncate then insert
- 十年磨一剑
- Box2D v2.1.0用户手册(6)——夹具(Fixtures)
- echart 地图 地图上的点 静态markPoint,动态markPoint
- 压力测试工具
- Using Binary Heaps in A* Pathfinding
- 关于虚函数