C加载lua配置,table交互, 调用lua函数

来源:互联网 发布:网易公开课优缺点知乎 编辑:程序博客网 时间:2024/04/29 04:39

转载自:http://www.cnblogs.com/stephen-liu74/archive/2012/07/20/2460634.html(做了些添加修改)
lua手册查询:http://cloudwu.github.io/lua53doc/contents.html
1. 基础:

    Lua的一项重要用途就是作为一种配置语言。现在从一个简单的示例开始吧。    //这里是用Lua代码定义的窗口大小的配置信息    //width = 200    //height = 300    下面是读取配置信息的C/C++代码: 
 1 #include <stdio.h> 2 #include <string.h> 3 #include <lua.hpp> 4 #include <lauxlib.h> 5 #include <lualib.h> 6  7 void load(lua_State* L, const char* fname, int* w, int* h) { 8     if (luaL_loadfile(L,fname) || lua_pcall(L,0,0,0)) { 9         luaL_error("Error Msg is %s.\n",lua_tostring(L,-1));10         return;11     }12     lua_getglobal(L,"width");13     lua_getglobal(L,"height");14     if (!lua_isnumber(L,-2)) {15         luaL_error("'width' should be a number\n" );16         return;17     }18     if (!lua_isnumber(L,-1)) {19         luaL_error("'height' should be a number\n" );20         return;21     }22     *w = lua_tointeger(L,-2);23     *h = lua_tointeger(L,-1);24 }25 26 27 int main()28 {29     lua_State* L = luaL_newstate();30     int w,h;31     load(L,"D:/test.lua",&w,&h);//文件路径设置为NULL表示从标准输入获取,VS ctrl+Z结束输入32     printf("width = %d, height = %d\n",w,h);33     lua_close(L);34     return 0;35 }
    int luaL_loadfile (lua_State *L, const char *filename);    #一个文件加载为 Lua 代码块.这个函数使用 lua_load 加载文件中的数据,代码块的名字被命名为filename    #如果 filename 为 NULL,.它从标准输入加载。 如果文件的第一行以 # 打头,则忽略这一行。    #mode 字符串的作用同函数 lua_load。    #lua_load 把一个编译好的代码块作为一个 Lua 函数压到栈顶。 否则,压入错误消息。    int luaL_error(lua_State *L, const char *fmt, ...);    #抛出一个错误。 错误消息的格式由 fmt 给出。    int lua_getglobal(lua_State *L, const char *name);    #把全局变量 name 里的值压栈,返回该值的类型。

2. table操作:
我们可以在C语言的代码中操作Lua中的table数据,这是一个非常非常方便且实用的功能。这样不仅可以使Lua代码的结构更加清晰,也可以在C语言代码中定义等同的结构体与之对应,从而大大提高代码的可读性。见如下代码:

 1 #include <stdio.h> 2 #include <string.h> 3 #include <lua.hpp> 4 #include <lauxlib.h> 5 #include <lualib.h> 6  7 void load(lua_State* L) { 8  9     if (luaL_loadstring(L,"background = { r = 0.30, g = 0.10, b = 0 }") 10         || lua_pcall(L,0,0,0)) {11         luaL_error("Error Msg is %s.\n",lua_tostring(L,-1));12         return;13     }14     lua_getglobal(L,"background");15     if (!lua_istable(L,-1)) {16         luaL_error("'background' is not a table.\n" );17         return;18     }19     lua_getfield(L,-1,"r");20     if (!lua_isnumber(L,-1)) {21         luaL_error("Invalid component in background color.\n");22         return;23     }24     int r = (int)(lua_tonumber(L,-1) * 255);25     lua_pop(L,1);26     lua_getfield(L,-1,"g");27     if (!lua_isnumber(L,-1)) {28         luaL_error("Invalid component in background color.\n");29         return;30     }31     int g = (int)(lua_tonumber(L,-1) * 255);32     lua_pop(L,1);33 34     lua_pushnumber(L,0.4);//推入一个值到栈顶用于setfield修改值35     lua_setfield(L,-2,"b");//自动弹出number36 37     lua_getfield(L,-1,"b");38     if (!lua_isnumber(L,-1)) {39         luaL_error("Invalid component in background color.\n");40         return;41     }42     int b = (int)(lua_tonumber(L,-1) * 255);43     printf("r = %d, g = %d, b = %d\n",r,g,b);44     lua_pop(L,1);45     lua_pop(L,1);//弹出table46     return;47 }48 49 int main()50 {51     lua_State* L = luaL_newstate();52     load(L);53     lua_close(L);54     return 0;55 }
int luaL_loadstring (lua_State *L, const char *s);//将一个字符串加载为 Lua 代码块。 这个函数使用 lua_load 加载一个零结尾的字符串 sint lua_getfield (lua_State *L, int index, const char *k);//把 table[k] 的值压栈, index是索引指向的table在栈的位置,k是table的键值//注意:假设一开始table的位置在栈顶,执行函数后table的位置为-2,-1位置为table[k]//可以用pop(L,1)从栈中弹出一个值,1代表一个,不代表位置void lua_setfield (lua_State *L, int index, const char *k);//做一个等价于 table[k] = v 的操作, index是索引指向的table在栈的位置,而v是栈顶的那个值。//这个函数将把这个值(v)弹出栈 

如何遍历table中所有元素(假设一开始table在栈顶)

1)如果table是一个以连续的整形作为key的table, 可以用下面方法

int size = lua_objlen(L,-1);//相关于#table  for(int i = 1; i <= size; i++)  {  lua_pushnumber(L, i);  lua_gettable(L, -2);  //这时table[i]的值在栈顶了  lua_pop(L, 1);//把栈顶的值移出栈,保证栈顶是table以便遍历。  };  

2)如果table中的key是任意值呢?可以用下面的方法:

lua_pushnill(L);  while(lua_next(L, -2))  {  //这时值在-1(栈顶)处,key在-2处。  lua_pop(L, 1);//把栈顶的值移出栈,让key成为栈顶以便继续遍历  }  
int lua_next (lua_State *L, int index);//从栈顶弹出一个键, 然后把索引指定的表中的一个键值对压栈 (弹出的键之后的 “下一” 对)。 如果表中//已无更多元素, 那么 lua_next 将返回 0 (什么也不压栈)。//它执行操作是这样的,以栈顶元素为key,先判断上一个key的值(这个值放在栈顶,如果是nil,则表示当前//取出的是table中第一个元素的值),然后得到当前的key和value。//这时先把栈顶出栈,将新key进栈,后将value进栈。这样栈顶就是table中第一个遍历到的元素的值。用完这//个值后,我们要把这个值出栈,让新key在栈顶以便继续遍历。当根据上一个key值算不出下一个key值时(其//实这时候key的是多少并不重要,只要不为nil就行,因为为nil会返回table的第一个元素),lua_next返回//0,结束循环。

下面的代码示例是在C语言代码中构造table对象,同时初始化table的字段值,最后再将table对象赋值给Lua中的一个全局变量。font>

 1 #include <stdio.h> 2 #include <string.h> 3 #include <lua.hpp> 4 #include <lauxlib.h> 5 #include <lualib.h> 6  7 void load(lua_State* L)  8 { 9     lua_newtable(L);//创建空表压栈10     lua_pushnumber(L,0.3);11     lua_setfield(L,-2,"r");//往表中添加元素12 13     lua_pushnumber(L,0.1);14     lua_setfield(L,-2,"g");15 16     lua_pushnumber(L,0.4);17     lua_setfield(L,-2,"b");18     lua_setglobal(L,"background");//弹出表,命名为background做为全局变量19 20     lua_getglobal(L,"background");//把全局变量压入栈21     if (!lua_istable(L,-1)) {22         luaL_error("'background' is not a table.\n" );23         return;24     }25     lua_getfield(L,-1,"r");26     if (!lua_isnumber(L,-1)) {27         luaL_error("Invalid component in background color.\n");28         return;29     }30     int r = (int)(lua_tonumber(L,-1) * 255);31     lua_pop(L,1);32     lua_getfield(L,-1,"g");33     if (!lua_isnumber(L,-1)) {34         luaL_error("Invalid component in background color.\n");35         return;36     }37     int g = (int)(lua_tonumber(L,-1) * 255);38     lua_pop(L,1);39 40     lua_getfield(L,-1,"b");41     if (!lua_isnumber(L,-1)) {42         luaL_error("Invalid component in background color.\n");43         return;44     }45     int b = (int)(lua_tonumber(L,-1) * 255);46     print("r = %d, g = %d, b = %d\n",r,g,b);47     lua_pop(L,1);48     lua_pop(L,1);49     return;50 }51 52 int main()53 {54     lua_State* L = luaL_newstate();55     load(L);56     lua_close(L);57     return 0;58 }
void lua_newtable (lua_State *L);//创建一张空表,并将其压栈。 它等价于 lua_createtable(L, 0, 0) 。 void lua_setglobal (lua_State *L, const char *name);//从堆栈上弹出一个值,并将其设为全局变量 name 的新值。 

3. 调用Lua函数:

调用函数的API也很简单。首先将待调用函数压入栈,再压入函数的参数,然后使用lua_pcall进行实际的调用,最后将调用结果从栈中弹出。见如下代码:

#include "stdafx.h"#include <iostream>#include <string.h>#include <math.h>#include <stdlib.h>using namespace std;extern "C"{#include "lua.h"#include "lualib.h"#include "lauxlib.h"#include "lprefix.h"};void load_border(lua_State *L, const char *fname, double x, double y)//c从lua配置文件中读取数据{    double z;    if (luaL_dofile(L, fname))        luaL_error(L, "cannot run config. file: %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)        luaL_error(L, "error running function 'f':%s", lua_tostring(L, -1));    if (!lua_isnumber(L, -1))        luaL_error(L, "funcrtion 'f' must return a number");    z = lua_tonumber(L, -1);    lua_pop(L, 1);    printf("%lf", z);}int _tmain(int argc, _TCHAR* argv[]){    lua_State *L = luaL_newstate();    double x = 2, y = 2;    load_border(L, "C:/Users/wujie03/Desktop/conf.lua",  x,  y);    //文件路径设置为NULL表示从标准输入获取    cin.get();    lua_close(L);    return 0;}

conf.lua

function f(x, y)     return x+yend

原文为return((x^2 * math.sin(y))/(1-x))用vs2013执行math.sin()报错了,还不知道原因

int luaL_dofile (lua_State *L, const char *filename);//加载并运行指定的文件。 它是用下列宏定义出来:      //(luaL_loadfile(L, filename) || lua_pcall(L, 0, LUA_MULTRET, 0))int lua_pcall (lua_State *L, int nargs, int nresults, int msgh);//在调用lua_pcall时,第二个参数是传给待调用函数的参数数量, 第三个参数是期望的结果数量,//第四个参数是一个错误处理函数的索引,0表示没有错误处理函数//lua_pcall会根据要求的数量来调整实际结果的数量,既压入nil或丢弃多余的结果//如果返回多个结果,那么第一个结果会最先压入,例如返回了3个结果,第一个索引就是-3//如果运行过程有任何错误,lua_pcall会返回一个非零值,并在栈中压入一条错误处理函数,
0 0
原创粉丝点击