Lua与C的交互(1)

来源:互联网 发布:高通垄断 知乎 编辑:程序博客网 时间:2024/05/21 06:58

示例小程序:获取Lua全局变量

//C中查询void load(lua_State *L,const char *fname,int *w,int *h){    if(luaL_loadfile(L,fname) || lua_pcall(L,0,0,0))        error(L,"cannot run config. file : %s",lua_tostring(L,-1));    lua_getglobal(L,"width");    lua_getglobal(L,"height");    if(!lua_isnumber(L,-2))        error(L,"'width' should be a number\n");    if(!lua_isnumber(L,-1))        error(L,"'height' should be a number\n");    *w = lua_tointeger(L,-2);    *h = lua_tointerger(L,-1);}

解释:
1.假设已经创建了一个Lua状态。这个函数调用luaL_loadfile从文件fname加载程序块,然后调用lua_pcall运行编译好的程序块。若发生错误(例如配置文件中的语法错误),这两个函数都会把错误消息压入栈,并返回一个非零的错误代码。此时,程序就调用lua_tostring从栈顶获取该消息
2.lua_getglobal:获取全局变量的值。其中,width处于索引-2上,height位于索引-1上(栈顶)。
3.lua_isnumber:检查值是否为数字
4.lua_tointeger:将这些值转换为整形,并赋予对应的参数变量。

示例小程序:获取Lua的table变量

--Lua配置background = {r = 0.30,g = 0.10,b = 0}//C中调用void load(lua_State *L,const char *fname,int *w,int *h){    if(luaL_loadfile(L,fname) || lua_pcall(L,0,0,0))        error(L,"cannot run config. file : %s",lua_tostring(L,-1));    lua_getglobal(L,"background");    if(!lua_istable(L,-1))        error(L,"'background' is not a table");    red = getfield(L,"r");    green = getfield(L,"g");    blue = getfield(L,"b");}#define MAX_COLOR 255/*假设table位于栈顶*/int getfield(lua_State *L,const char * key){    int result;    lua_pushstring(L,key);    lua_gettable(L,-2);             /*获取background[key]*/    if(!lua_isnumber(L,-1))        error(L,"invalid component in background color“);    result = (int)lua_tonumber(L,-1)*MAX_COLOR;    lua_pop(L,1);    return result;}

1.使用lua_getglobal获取全局变量background的值,并确认其是一个table.然后,使用getfield获取颜色中的各个分量。
2.使用lua_pushstring压入key后,table位于索引-2的位置。在返回前,getfield弹出从栈中检索到的值,并使栈保持为调用前的样子。
3.lua_getfield(L,-1,key),其中-1是table的索引相当于:
lua_pushstring(L,key);
lua_gettable(L,-2); /获取background[key]/

在C中创建Lua的table

//C中调用#define MAX_COLOR 255struct ColorTable{    char *name;    unsigned char red,green,blue;}colortable[] = {    {"WHITE",MAX_COLOR,MAX_COLOR,MAX_COLOR},    {"RED",MAX_COLOR,0,0},    {"GREEN",0,MAX_COLOR,0},    {NULL,0,0,0,0}          /*结尾*/};/*假设table位于栈顶*/void setfield(lua_State *L,const char * index,int value){    lua_pushstring(L,index);    lua_pushnumber(L,(double)value/MAX_COLOR);    lua_settable(L,-3);}//等价于上面的函数//void setfield(lua_State *L,const char *index,int value)//{//  lua_pushnumber(L,(double)value/MAX_COLOR);//  lua_setfield(L,-2,index);//}void setcolor(lua_State *L,struct ColorTable *ct){    lua_newtable(L);             /*创建一个table*/    setfield(L,"r",ct->red);     /*table.r = ct->r*/    setfield(L,"g",ct->green);   /*table.g = ct->g*/    setfield(L,"b",ct->blue);    /*table.b = ct->b*/    lua_setglobal(L,ct->name);   /*'name' = table*/}

解释
1.lua_newtable:创建一个空的table,并将它压入栈中。
2.lua_setglobal:弹出table,并根据名称将其赋予全局变量。

调用Lua函数

--Lua配置function f(x,y)    return (x^2 * math.sin(y))/(1-x)end//C调用Lua函数double f(double x, double y){    double z;    /*压入函数和参数*/    lua_getglobal(L,"f");       /*待调用的函数*/    lua_pushnumber(L,x);        /*压入第一个参数*/    lua_pushnumber(L,y);        /*压入第二个参数*/    /*完成调用(2个参数,一个结果)    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");    z = lua_tonumber(L,-1);    lua_pop(L,1);          /*弹出返回值*/    return z;}

解释:
1.lua_pcall:第二个参数是传给待调用函数的参数数量,第三个参数是期望的结果数量,第四个参数是一个错误处理函数的索引。就像Lua的赋值一样,lua_pcall会根据要求的数量来调整实际结果的数量,即压入nil或丢弃多余的结果。在压入结果前,lua_pcall会先删除栈中的函数及其参数。如果一个函数会返回多个结果,那么第一个结果最先压入。例如,函数返回了3个结果,第一个索引就是-3,最后一个索引是-1.如果在lua_pcall的运行过程中有任何错误,lua_pcall会返回一个非零值,并在栈中压入一条错误消息。不过即使如此,她仍会弹出函数及其参数。然而,在压入错误消息前,如果存在一个错误处理函数,lua_pcall就会先调用它。通过lua_pcall的最后一个参数可以指定这个 错误处理函数。零表示没有错误处理函数,那么最终的错误消息就是原来的消息。若传入非零的参数,那么这个参数就应该是一个错误处理函数在栈中的索引。因此,错误处理函数必须先压入栈中,也就是必须位于待调用函数及其参数的下面。对于普通的错误,lua_pcall会返回错误代码LUA_ERRUN。但有两种特殊的错误情况,不会运行错误处理函数。第一种是内存分配错误,对于这类错误,lua_pcall总是返回LUA_ERRMEM.第二类错误则发生在Lua运行错误处理函数时,在这种情况中,是没有必要再次调用错误处理函数的,因此lua_pcall会立即返回错误代码LUA_ERRERR.

最后的通用函数:

#include<stdarg.h>void call_va(const char *func,const char *sig,...){    va_list v1;    int narg,nres;        /*参数和结果的数量*/    va_start(v1,sig);    lua_getglobal(L,func);  /*压入函数*/    //压入参数    for(narg = 0; *sig; narg++)  /*遍历所有参数*/    {        /*检查栈中空间*/        luaL_checkstack(L,1,"to many arguments");        switch(*sig++)        {            case 'd':     /*double参数*/                lua_pushnumber(L,va_arg(v1,double));                break;            case 'i':     /*int参数*/                lua_pushinteger(L,va_arg(v1,int));                break;            case 's':     /*字符串参数*/                lua_pushstring(L,va_arg(v1,char *));                break;            case '>':     /*参数结束*/                goto endargs;            default:                error(L,"invalid option (%c)",*(sig-1));        }    }    endargs:    nres = strlen(sig);    /*期望的结果数量*/    if(lua_pcall(L,narg,nres,0) != 0)      /*完成调用*/        error(L,"error calling '%s' : %s",func,lua_tostring(L,-1));    //检索结果    nres = -nres;      /*第一个结果的栈索引*/    while(*sig)        /*遍历所有结果*/    {        switch(*sig)        {            case 'd': /*double结果*/                if(!lua_isnumber(L,nres))                    error(L,"wrong result type");                *va_arg(v1,double*) = lua_tonumber(L,nres);                break;            case 'i': /*int结果*/                if(!lua_isnumber(L,nres))                    error(L,"wrong result type");                *va_arg(v1,int*) = lua_tointeger(L,nres);                break;            case 's': /*string结果*/                if(!lua_isstring(L,nres))                    error(L,"wrong result type");                *va_arg(v1,const char**) = lua_tostring(L,nres);                break;            default:                error(L,"invalid option(%c)",*(sig-1));        }        nres++;    }    va_end(v1);}
原创粉丝点击