Lua与C的交互(0)

来源:互联网 发布:网络病毒软件下载 编辑:程序博客网 时间:2024/05/17 07:17

1.编译器:http://files.luaforge.net/releases/luaforwindows/luaforwindows
Lua和C语言通信的主要方法是一个无所不在的虚拟栈。几乎所有的API调用都会操作这个栈上的值。所有的数据交换,无论是Lua到C语言或C语言到Lua都通过这个栈来完成。此外,还可以用这个栈来保存一些中间结果。栈可以解决Lua和C语言之间存在的两大差异,第一种差异是Lua使用垃圾收集,而C语言要求显示地释放内存,第二种是Lua使用动态类型,而C语言使用静态类型。

C中调用Lua示例代码

#include<stdio.h>#include<string.h>#include "lua.h"#include "lauxlib.h"#include "lualib.h"int main(void){    char buff[256];    int error;    lua_State *L = luaL_newstate();    /*打开Lua*/    luaL_openlibs(L);                  /*打开标准库*/    while(fgets(buff,sizeof(buff),stdin) != NULL)    {        error = luaL_BUFFER(L,buff,strlen(buff),"line")|| lua_pcall(L,0,0,0);        if(error)        {            fprintf(stderr,"%s",lua_tostring(L,-1));            lua_pop(L,1);        /*从栈中弹出错误消息        }    }    lua_close(L);    return 0;}

代码解析:
1.lua.h : lua.h定义了lua提供了的基础函数,包括创建Lua环境,调用Lua函数(如lua_pcall)读写Lua环境中全局变量,以及注册供Lua调用的新函数等。lua.h中定义的所有内容都有一个lua_前缀。Lua库中没有定义任何全局变量。它将所有的状态都保存在动态结构lua_State中,所有的C API都要求传入一个指向该结构的指针。这种实现使得Lua可以重入(reenter),稍加修改即可用于多线程的代码中
2.lauxlib.h : 头文件lauxlib.h定义了辅助库(auxiliary library,auxlib)提供的函数。它的所有定义都以luaL_开头(如luaL_loadbuffer)。辅助库是一个使用lua.h中API编写出的一个较高的抽象层。Lua的所有标准编写都用到了辅助库。基础API的设计保持原子性和正交性,而辅助库则侧重于解决具体的任务。
3.luaL_newstate函数用于创建一个新环境(或状态)。当luaL_newstate创建一个新环境时,新环境中没有包含预定义的函数,甚至没有print.为了使Lua保持小巧,所有的标准库都被组织到了不同的包中。这样便可以忽略那些不需要的包。
4.luaL_openlibs:在头文件lualib.h中定义了打开这些库的函数,而辅助库函数luaL_openlibs则可以打开所有的标准库。当创建好一个状态,并在其中加载了标准库后,就可以解释用户的输入了。
5.luaL_loadbuffer:编译用户输入的每行内容。如果没有错误,此调用返回0,并向栈中压入编译后的程序块.
6.lua_pcall:将luaL_loadbuffer编译后的程序块从栈中弹出,并在保护模式中运行它。与luaL_loadbuffer类似,lua_pcall返回0表示没有错误。若发生错误,那么这些函数就会向栈中压入一条错误消息。用lua_tostring可以获取这条消息,打印后可以用lua_pop把它从栈中删除
7.lua_close:关闭Lua状态,并结束整个程序

压入元素:
1.void lua_pushnil(lua_State *L):压入常量nil
2.void lua_pushboolean(lua_State *L,int bool):压入布尔类型
3.void lua_pushnumber(lua_State *L,lua_Number n):压入双精度浮点数,lua_Number是Lua中的数字类型。默认为双精度浮点数,但有些发行版本为了适应某种硬件受限的环境,会将数字类型改为单精度浮点数或长整数。
4.void lua_pushinteger(lua_State *L,lua_Integer n):压入整数,lua_Integer是一种整数类型,它足以存储大型字符串的长度,通常定义为ptrdiff_t类型
5.void lua_pushlstring(lua_State L,const char *s,size_t len):压入任意字符串(char 及长度),Lua中的字符串不是以零结尾的,他们可以包含任意二进制数据。因此,它们必须同时保存一个显式的长度。
6.void lua_pushstring(lua_State *L,const char *s):压入以零结尾的字符串,通过strlen来计算字符串的长度。
7.int lua_checkstack(lua_State *L,int sz):调用lua_checkstack来检查栈中是否有足够的空间。

查询元素:
API使用索引来引用栈中的元素。第一个压入栈中的元素索引为1;第二个压入的元素索引是2,依此类推知道栈顶。还可以为栈顶为参考物,使用负数的索引来访问栈中的元素。此时-1表示栈顶元素(最后压入的元素),-2表示栈顶下面的元素。依此类推。
1.int lua_is (lua_State *L,int index):检查一个元素是否为特定的类型,其中可以是任意Lua类型。如lua_isnumber,lua_isstring和lua_istable等。实际上lua_isnumber不会检查值是否为数字类型,而是检查值是否能转换为数字类型。lua_isstring也具有同样的行为。因此,对于任何数字,lua_isstring都返回真。
2.lua_type,它会返回栈中元素的类型。每种类型都对应于一个常量,这些常量定义在头文件lua.h中,它们是LUA_TNIL,LUA_TBOOLEAN,LUA_TNUMBER,LUA_TSTRING,LUA_TTABLE,LUA_TTHERAD,LUA_TUSERDATA和LUA_TFUNCTION.
3.lua_to*函数用于从栈中获取一个值.
例:int lua_toboolean(lua_State *L,int index)
lua_Number lua_tonumber(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):函数会返回一个指向内部字符串副本的指针,并将字符串的长度存入最后一个参数len中。这个内部副本不能修改,返回类型中的const也说明了这点。Lua保证只要这个对应的字符串值还在栈中,那么这个指针就是有效的。当Lua调用的一个C函数返回时,Lua就会清空它的栈,这就形成了一条规则,不要在C函数之外使用在C函数内获得的指向Lua字符串的指针。所有lua_tolstring返回的字符串在其末尾都会有一个额外的零,不过这些字符串的中间可能也会有零。字符串长度通过第三个参数len返回,这才是真正的字符串长度。
size_t lua_objlen(lua_State *L,int index):lua_objlen函数可以返回一个对象的长度。对于字符串和table,这个值是长度操作符#的结果。这个函数还可以用于获取一个”完全userdata(full userdata)的大小”
如果指定的元素不具有正确的类型,调用这些函数也不会有问题。在这种情况下,lua_toboolean,lua_tonumber,lua_tointeger和lua_objlen会返回0,而其他函数会返回NULL.返回0并不是很有用,但ANSI C也没有提供其他可以表示错误的值。至于其他lua_to*函数,通常不先使用lua_is*函数,只需在调用它们之后测试返回结果是否为NULL就可以了。

示例:

static void stackDump(lua_State *L){    int i;    int top = lua_gettop(L);    for(i = 1; i < top; i++) /*遍历所有层*/    {        int t = lua_type(L,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:{          /*其他值*/                print("%s",lua_typename(L,t));                break;            }        }        printf(" ");           /*打印一个分隔符*/    }    print("\n");               /*列表结尾*/}

其他栈操作
1.int lua_gettop(lua_State *L):返回栈中元素的个数,也可以说是栈顶元素的索引。lua_settop将栈顶设置为一个指定的位置,即修改栈中元素的数量。如果之前的栈顶比新位置的更高,那么高出来的这些元素会被丢弃。反之,会向栈中压入nil来补足大小。调用lua_settop(L,0)能清空栈。也可以是用负数索引来使用lua_settop。另外,API根据这个函数还提供了一个宏,用于从栈中弹出n个元素:#define lua_pop(L,n) lua_settop(L,-(n)-1)
2.void lua_settop(lua_State *L,int index)
3.void lua_pushvalue(lua_State *L,int index):会将指定索引上值的副本压入栈。
4.void lua_remove(lua_State *L,int index):删除指定索引上的元素,并将该位置之上的所有元素下移以填补空缺。
5.void lua_insert(lua_State *L,int index):会上移指定位置之上的所有元素以开辟一个槽的空间,然后将栈顶元素移到该位置。
6.void lua_replace(lua_State *L,int index):弹出栈顶的值,并将该值设置到指定索引上,但它不会移动任何东西。

示例:

#include<stdio.h>#include "lua.h"#include "lauxlib.h"static void stackDump(lua_State *L){    int t = lua_type(L,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:{          /*其他值*/                print("%s",lua_typename(L,t));                break;            }        }        printf(" ");           /*打印一个分隔符*/    }    print("\n");               /*列表结尾*/}int main(void){    lua_State *L = luaL_newstate();    lua_pushboolean(L,1);    lua_pushnumber(L,10);    lua_pushnil(L);    lua_pushstring(L,"Hello");    stackDump(L);    lua_pushvalue(L,-4);    stackDump(L);    lua_replace(L,3);    stackDump(L);    lua_settop(L,6);    stackDump(L);    lua_remove(L,-3);    stackDump(L);    lua_settop(L,-5);    stackDump(L);    lua_close(L);    return 0;}
原创粉丝点击