如何使用CAPI存取操作Lua中的值,一组能使C与Lua交互的函数
Lua_C数据交互使用一个虚拟栈:luaState
Lua和C的差异:
1、Lua使用垃圾回收,C使用显式的内存释放
2、Lua使用动态类型,C使用静态类型lua头文件介绍:
lua.h定义了lua提供的基础函数,包括创建Lua环境(LuaState),调用Lua函数(lua_pcall)...
lauxlib.h定义了辅助库提供的函数,以luaL_开头
构建Lua环境执行Lua代码的简单例子:
<span style="font-size:14px;">#include <stdio.h>
#include <string.h>
extern "C" {
#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_loadbuffer(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;
}</span>
使用栈交互:
优点: 除了在c/c++上方便使用还可以轻松应用到其他语言
如果在C中保存Lua table变量,Lua的垃圾回收无法搜索出这个table不是垃圾文件
在Lua中调用该栈的时候,只会改变栈顶,而使用C可以自由检索中间元素
压入栈元素的CAPI:
lua_pushxxx : lua_pushnil(L),lua_pushboolean(L,bool)
压入元素需要提前检查空间:int lua_checkstack(lua_State* L,int sz)
查询栈元素的CAPI:
规则:关于索引->第一个压入栈的元素索引为1;第二个压入索引为2...直到栈顶
还可以以栈顶为参考物:-1表示栈顶元素,-2表示栈顶下面的元素...知道栈底
例子:lua_tostring(L,-1)会将栈顶的值作为一个字符串返回
检查栈中元素的类型:int lua_is*(lua_State* L, int index) : lua_isnumber,lua_istable...
返回栈中元素的类型:lua_type(L,index) : LUA_TNIL,LUA_TBOOLEAN,LUA_TTABLE....
从栈中获取一个值: lua_to*(L,index): lua_toboolean,lua_objlen
其他栈操作:
int lua_gettop(L) :返回栈元素的个数,或者是栈顶的索引
void lua_settop(L,int index) :使用lua_settop(L,0)可以清空栈,用负数索引可以从栈弹出元素,大于len则用栈顶元素填充
void lua_pushvalue(L,index) :将指定索引元素副本压入栈顶
void lua_remove(L,index) :删除指定索引元素,下移填补
void lua_insert(L,index) :上移所有元素开辟一个槽空间
void lua_replace(L,index) : 弹出栈顶的值,设置到指定索引上(原栈顶移除)
例子:
<span style="font-size:14px;">
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);
getwchar();</span>
CAPI中的错误处理
使用setjmp机制
“无保护”模式:当Lua发生错误时,Lua会调用一个“紧急”函数,然后Lua会结束应用程序
不会抛出异常的函数:luaL_newstate,lua_load,lua_pcall,lua_close
如果内存分配错误,不想结束应用程序的方法:
1、设置一个“紧急”函数不要把控制权返回给Lua
2、代码在“保护模式”下运行(常用)
luaL_loadfile(L,fname): 从fname的文件中加载程序块
lua_getglobal(L,"width") :将对应的全局变量值压入栈中
在栈中对table的操作:
1、lua_gettable(L,index):查找指定table以栈顶为key的value
详细:index是table在相对栈顶的位置,取栈顶元素为key找value,然后将栈顶的key替换为value,这样栈顶就是key对应的value值
lua_getfield(L,-1,key):一个lua_gettable的特化版本,不需要将key压入栈顶
2、lua_settable(L,index)
详细:将key和value一次压入栈,index为table在当前栈的位置,lua_settable压入对应key和value后,弹出key和vlaue
lua_setfield(L,-2,index):lua_settable的特化,value压入栈顶,index为key
3、lua_newtable(L):压入一个空的table
4、lua_pcall(L,pNum,rNum,errNum):调用Lua函数,成功则返回0
pNum:函数的参数个数
rNum:函数的返回值个数
errNum:错误处理函数的索引
发生错误会返回一个非零值,并在栈中压入一条错误信息
int invokeLuaFun(int x,int y){
lua_State* L = luaL_newstate();
luaL_openlibs(L); //打开标准库
if(luaL_loadfile(L,"config.lua") || lua_pcall(L,0,0,0))
error(L,"cannot run config.lua:%s",lua_tostring(L,-1));
lua_getglobal(L,"f");
lua_pushnumber(L,x);
lua_pushnumber(L,y);
if(lua_pcall(L,2,1,0)!=0)
error(L,"error running function 'f':%s",lua_tostring(L,-1));
if(!lua_isnumber(L,-1))
error(L,"function 'f' must return a number");
int z = lua_tonumber(L,-1);
lua_pop(L,1); //弹出栈顶
return z;
}
------------------------------------------------------------------------
void lua_rawgeti(lua_State *L,int index,int key);
void lua_rawseti(lua_State *L,int index,int key);
void lua_pushnumber(lua_State *L,int key);
void lua_insert(lua_State *L,int index);
void lua_rawget(lua_State *L,int index);
void lua_rawset(lua_State *L,int index);
void luaL_checktype(Lua_State *L,int index, TYPE) TYPE:LUA_TTABLE,LUA_TFUNCTION
int luaL_checktype(lua_State *L,int index);
void lua_pushvalue(lua_State *L,int index);
void lua_call(lua_State* L,int index,int key);