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");//自动弹出number
36
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);//弹出table
46 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 加载一个零结尾的字符串 s
int 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+y
end
原文为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会返回一个非零值,并在栈中压入一条错误处理函数,