首先,你需要下载Lua。你需要从Lua下载页面去下载源代码。如果你需要编译好了的二进制库,你能在LuaBinaries 中找到你想要的库(lib or dll)。

现在,我们需要安装Lua。在Linux下,你应该先解压文件,然后以root用户在命令行键入"make linux"和"make linux install"。如果你需要帮助,请参考源代码文件夹中的INSTALL文件。现在,我下载了windows平台下的二进制库包并把它们解压到"C:\Program Files\lua5.1"。

在Linux下不需要我们做任何设置,但是在windows平台下我们必须配置Visual C++,以便让编译器和连接器找到Lua文件。

打开Visual C++,选择Tools菜单中的选项菜单。 
展开"项目",并选择"VC++ 目录"。 
选择"包含文件",添加一个新路径"C:\Program Files\lua5.1\include"。 
在选择"库文家",添加路径"C:\Program Files\lua5.1\lib\dll"(这里假设你下载的库为dll,你也可以下载静态链接库)。 
确定。  
现在你可以开始编译你的第一个Lua应用了。

使用Lua开始你的第一个程序
这个程序简短且直接,下面做一点说明:

lua_open()返回一个指向Lua解释器的一个指针。 
luaL_openlibs()用于装载Lua库,它提供了一些简单的函数,如:print。 
通过调用luaL_dofile()执行脚本。它的作用是读取并解释脚本。 
最后,通过lua_close()函数关闭Lua。 
保存文件为luatest.cpp。如果你直接使用C而不是C++,将文件名改为luatest.c,然后将extern "C"删除。

#include <stdio.h>
extern "C" {
  #include "lua.h"
  #include "lualib.h"
  #include "lauxlib.h"
 }/* Lua解释器指针 */
 lua_State* L;int main ( int argc, char *argv[] )
 {
  /* 初始化Lua */
  L = lua_open(); /* 载入Lua基本库 */
  luaL_openlibs(L); /* 运行脚本 */
  luaL_dofile(L, "test.lua"); /* 清除Lua */
  lua_close(L); /* 暂停 */
  printf( "Press enter to exit…" );
  getchar(); return 0;
 }
 下面是test.lua的内容。-- simple test
print "Hello, World!"


编译
在Linux下,在命令行键入:

g++ luatest.cpp -llua -ldl -o luatest然后,键入下列命令运行:
./luatest如果没有问题,程序将在终端输出Hello, World!


在Lua中定义函数是相当简单的。Lua函数以关键字"function"开头,后面跟随函数名,然后是参数列表。函数定义以关键字"end"结束。Lua函数能够接受多个参数,而且可以返回多个参数。

下面是一个实现两个数相加并返回结果的Lua函数。我们将它保存为"add.lua"文件。

-- add two numbers
function add ( x, y )
return x + y
end

在Lua入门中,我们已经知道调用luaL_dofile()就是执行脚本。因为在本文中我们只定义了一个函数,故只需简单地调用luaL_dofile()函数就能执行add函数。

我在前面已经说过,Lua函数能够接受多个参数,返回多个结果。这是用栈来实现的。

为了调用一个Lua函数,首先需要将函数压入栈中。再将参数压入。然后,调用lua_call()去调用Lua函数。函数调用完成之后,返回值存在于栈中。所有这些步骤将被展示在luaadd()函数定义中。

  1. 调用lua_getglobal()将add()函数压入栈中。
  2. 调用lua_pushnumber()将第一个参数x压入栈中。
  3. 同样,调用lua_pushnumber()将第二个参数y压入栈中。
  4. 调用lua_call(),其参数的意思是两个参数,一个返回值。
  5. 现在,我们可以利用lua_tointeger()获得整型返回值。
  6. 最后,调用lua_pop()将值从栈中移出。

保存文件为luaadd.cpp。如果你直接使用C而不是C++,将文件名改为luaadd.c,然后将extern "C"删除。

#include <stdio.h>
extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}
/* 指向Lua解释器的指针 */
lua_State* L;
int luaadd ( int x, int y )
{
int sum;
/* 通过名字得到Lua函数 */
lua_getglobal(L, "add");
/* 第一个参数 */
lua_pushnumber(L, x);
/* 第二个参数 */
lua_pushnumber(L, y);
/* 调用函数,告知有两个参数,一个返回值 */
lua_call(L, 2, 1);     /* 调用函数,告知有两个参数,一个返回值 */  lua_pcall(L, 2, 1,0);      //调用此函数会自动将参数弹出栈,只保留返回值 最后参数是错误检测;
/* 得到结果 */
sum = (int)lua_tointeger(L, -1);
lua_pop(L, 1); 返回值出栈,恢复栈中的元素
return sum;
}
int main ( int argc, char *argv[] )
{
int sum;
/* 初始化Lua */
L = lua_open();
/* 载入Lua基本库 */
luaL_openlibs(L);
/* 载入脚本 */
luaL_dofile(L, "add.lua");
/* 调用Lua函数 */
sum = luaadd( 10, 15 );
/* 显示结果 */
printf( "The sum is %d\n", sum );
/* 清除Lua */
lua_close(L);
/* 暂停 */
printf( "Press enter to exit…" );
getchar();
return 0;
}
编译
在Linux下,在命令行键入:
g++ luaadd.cpp -llua -ldl -o luaadd
然后,键入下列命令运行:
./luaadd
如果没有问题, 程序将显示结果为: "The sum is 25"。

在Visual C++你将需要进行下列步骤:

  1. 创建一个新的空Win32控制台应用工程。
  2. 将"luatest.cpp"加入你的工程。
  3. 选择项目菜单中的属性菜单。
  4. 在"连接器"的"输入"栏目的"附加依赖项"中输入"lua5.1.lib"。
  5. 确定。

此时,按F7构建程序。

如果你采用的是dll库,请确保将其放在应用程序的目录中或者windows系统能够找到它的地方。如果你采用的是静态连接库,则不需要。 

全局变量

全局变量在Lua中也很好处理。就像我们看到的,lua_getglobal()将一个Lua全局变量压入栈中。例如,在Lua脚本中包含一个全局变量z,下面代码的功能就是得到它的值:

lua_getglobal(L, "z");
z = (int)lua_tointeger(L, -1);
lua_pop(L, 1);
相应地,lua_setglobal()函数能够设置全局变量地值。下面这段代码演示了如何将Lua全局变量z的值变为10:
lua_pushnumber(L, 10);
lua_setglobal(L, "z");
应该记住:在Lua中,我们没有必要显式定义一个全局变量。如果全局变量不存在,调用lua_setglobal()将为你创建一个。

错误检查
if (!lua_isnumber(L, i)) {
 lua_pushstring(L, "Incorrect argument to 'average'");
  lua_error(L);
 }


添加这样的检查很容易,同时这样也让调试更容易。当处理用两种不同语言编写的程序的时候,这显得相当重要。

// 调用lua的函数,都是通过压栈出栈来完成的   
    // 为表执行一个t[k]=v的操作,则需要先将k压栈,再将v压栈,再调用操作函数   
    // 这个操作函数会使用栈上的元素,并“可能”将弹出元素和压入元素   
    // lua_rawset直接赋值(不触发metamethods方法)。   
       
    // lua_rawset/lua_settable使用:   
    // 它从栈中获取参数。以table在栈中的索引作为参数,   
    // 并将栈中的key和value出栈。   
    // lua_pushnumber函数调用之前,   
    // table是在栈顶位置(索引为-1)。index和value入栈之后,   
    // table索引变为-3。   
     lua_pushnumber( state, 1 );   
     lua_pushnumber( state, 45 );   
     lua_rawset( state, -3 );    
// set the number of elements (index to the last array element)   
    // lua_pushliteral压入一个字符串,不需要指定长度   
    // 如果lua_pushlstring,则需要指定长度   
     lua_pushliteral( state, "n" );   
     lua_pushnumber( state, 2 );   
     lua_rawset( state, -3 );  
 // set the name of the array that the script will access   
    // Pops a value from the stack and sets it as the new value of global name.  
    // 从栈顶弹出一个值,并将其设置全局变量"arg"的新值。   
     lua_setglobal( state, "arg" );


//定义函数(返回table)
 int func_return_table(lua_State *L)
 {
  lua_newtable(L);//创建一个表格,放在栈顶
  lua_pushstring(L, "mydata");//压入key
  lua_pushnumber(L,66);//压入value
  lua_settable(L,-3);//弹出key,value,并设置到table里面去 lua_pushstring(L, "subdata");//压入key
  lua_newtable(L);//压入value,也是一个table
  lua_pushstring(L, "mydata");//压入subtable的key
  lua_pushnumber(L,53);//value
  lua_settable(L,-3);//弹出key,value,并设置到subtable lua_settable(L,-3);//这时候父table的位置还是-3,弹出key,value(subtable),并设置到table里去
  lua_pushstring(L, "mydata2");//同上
  lua_pushnumber(L,77);
  lua_settable(L,-3);
  return 1;//堆栈里现在就一个table.其他都被弹掉了。
 }





如果要返回一个table: 
 

lua_newtable(L);  //创建一个表格,放在栈顶 
   lua_pushstring(L, "mydata");  //压入key 
   lua_pushnumber(L,66);  //压入value 
   lua_settable(L,-3);  //弹出key,value,并设置到table里面去 
   lua_pushstring(L, "subdata");  //压入key 
   lua_newtable(L);  //压入value,也是一个table 
   lua_pushstring(L, "mydata");  //压入subtable的key 
   lua_pushnumber(L,53);  //value 
   lua_settable(L,-3);  //弹出key,value,并设置到subtable 
   lua_settable(L,-3);  //这时候父table的位置还是-3,弹出key,value(subtable),并设置到table里去 
   lua_pushstring(L, "mydata2");  //同上 
   lua_pushnumber(L,77); 
   lua_settable(L,-3); 
   return 1;  //堆栈里现在就一个table.其他都被弹掉了。


如果要返回一个数组,用如下代码:(注意那个关于trick的注释,我在等官方的解释。经过验证,这个问题只在windows版本调用dll中方法的时候出现。WinCE正常)



lua_pushstring(L,"arri"); 
   lua_newtable(L); 
   { 
     //a trick:otherwise the lua engine will crash. This element is invisible in Lua script 
     lua_pushnumber(L,-1); 
     lua_rawseti(L,-2,0); 
     for(int i = 0; i < arri.size();i++) 
     { 
       lua_pushnumber(L,arri); 
       lua_rawseti(L,-2,i+1); 
     }
    }
    lua_settable(L,-3);
   这样产生的数组可以在Lua中如下遍历: 
 

 
  for i,v in ipairs(data.arri) do 
     print(v) 
   end
   或者是
   for i=1,table.getn(data.arri) do 
     print(data.arri) 
   end
   只有数组才能这样,name,value构成的Record不行,table.getn也只对数组有效。




lua中调用C函数

将用C++创建一个函数,告诉Lua解释器它的情况,最后从Lua中调用它并使用其结果。我在后面也将谈一谈Lua程序中的错误检查。

定义函数
第一步是定义函数。所有在Lua中被调用的C/C++函数将使用下面一类指针进行调用:

typedef int (*lua_CFunction) (lua_State *L);换句话说,函数必须要以Lua解释器作为唯一的参数,并且返回一个唯一的整数。由于用一个Lua解释器作为参数,因此函数实际上能够从栈中取得任意数量的参数。在后面我们将看到,返回的整数实际上是被压入栈的值的个数。通过如此容易的封装,就能满足你在Lua中调用C++函数的需求。

下面给出的C++函数average()演示了如何接受多个参数且返回超过一个值。记住,该函数是一个与上面typedef相匹配的函数。

lua_gettop函数返回栈顶的索引值。因为在Lua中栈是从1开始编号的,因此该函数获得的值就是参数的个数。 
在for循环中计算所有参数之和。 
调用lua_pushnumber()将参数的平均值压栈。 
将参数之和压入栈中。 
最后,函数返回2,说明有两个返回值在栈中。  
现在C++函数已经被定义好了,我们必须将它告诉Lua解释器。这将在main函数中初始化Lua解释器和载入库完成之后完成:

 /* 注册函数 */
 lua_register(L, "average", average);
保存文件为luaavg.cpp。如果你直接使用C而不是C++,将文件名改为luaavg.c,然后将extern "C"删除。

#include <stdio.h>
extern "C" {
  #include "lua.h"
  #include "lualib.h"
  #include "lauxlib.h"
 }/* 指向Lua解释器的指针 */
 lua_State* L;static int average(lua_State *L)
 {
   /* 得到参数个数 */
  int n = lua_gettop(L);
  double sum = 0;
  int i; /* 循环求参数之和 */
  for (i = 1; i <= n; i++)
  {
   /* 求和 */
   sum += lua_tonumber(L, i);
  } /* 压入平均值 */
  lua_pushnumber(L, sum / n); /* 压入和 */
  lua_pushnumber(L, sum);  /* 返回返回值的个数 */
  return 2;
 }int main ( int argc, char *argv[] )
 {
  /* 初始化Lua */
  L = lua_open(); /* 载入Lua基本库 */
  luaL_openlibs(L); /* 注册函数 */
  lua_register(L, "average", average); /* 运行脚本 */
  luaL_dofile(L, "avg.lua"); /* 清除Lua */
  lua_close(L); /* 暂停 */
  printf( "Press enter to exit…" );
  getchar(); return 0;
 }
 下面是以5个参数调用average函数并且显示两个返回值的Lua脚本,我们将其保存为avg.lua:-- call a C++ function
avg, sum = average(10, 20, 30, 40, 50)
print("The average is ", avg)
 print("The sum is ", sum)






lua是一个跨平台的脚本语言,在linux下也可以使用,但是我目前只使用过windows,这篇文章也是在windows下的编程。


1.lua的简介

百度百科的简介:

Lua 是一个小巧的脚本语言。是巴西里约热内卢天主教大学(Pontifical Catholic University of Rio de Janeiro)里的一个研究小组,由Roberto Ierusalimschy、Waldemar Celes 和 Luiz Henrique de Figueiredo所组成并于1993年开发。 其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。Lua由标准C编写而成,几乎在所有操作系统和平台上都可以编译,运行。Lua并没有提供强大的库,这是由它的定位决定的。所以Lua不适合作为开发独立应用程序的语言。Lua 有一个同时进行的JIT项目,提供在特定平台上的即时编译功能。


2.下载lua

lua官网的下载页面:http://www.lua.org/download.html


3.lua包含的文件

下载后的lua是一个压缩包,解压后可以获得doc和src文件夹,还有makefile和readme文件。

doc文件夹下主要有lua的api文档

src文件夹包含lua的源码

(lua压缩包并不包含lib文件,lib文件直接通过vs去编译lua源代码就可以生成lib了,方法见第四步)


4.生成lua lib文件。

使用visual studio添加静态库项目(静态库项目的生成方法见此链接)


5.使用lua

在生成lib文件的步骤中的链接能看到如何在项目中使用lib,lua的使用同样需要使用lib,除了添加lib,还需要添加lauxlib.h,lua.h,luaconf.h,lualib.h这几个头文件。

关于lua的使用,我直接用代码说明吧。

以下代码演示了lua的栈操作 ,执行内存脚本,加载脚本中定义的变量,执行脚本中定义的无参函数,执行脚本中定义的有参函数,脚本中调用C++函数等操作。



[cpp] view plaincopy


1. // lua_test.cpp : 定义控制台应用程序的入口点。  
2. //  
3.   
4. #include "stdafx.h"  
5.   
6. #include <iostream>    
7. #include <string>    
8.   
9. extern "C"  
10. {  
11. #include "lua.h"  
12. #include "lualib.h"  
13. #include "lauxlib.h"  
14. }  
15.   
16. using namespace std;   
17.   
18.   
19. int fcAdd(lua_State *lu)    
20. {    
21. int a = lua_tointeger(lu, 1);    
22. int b = lua_tointeger(lu, 2);    
23. //结果压栈    
24. return 1;           //返回1个结果    
25. }    
26.   
27.   
28. int _tmain(int argc, _TCHAR* argv[])  
29. {  
30.   
31. int nret = 0;    
32.   
33. /*创建Lua对象*/  
34.     lua_State* lu = luaL_newstate();  
35.     luaL_openlibs(lu);  
36.   
37.   
38. /*栈操作  */  
39. //压入一个int类型的数据,数值为1  
40.     lua_pushinteger(lu, 1);    
41. //压入一个int类型的数据,数值为3  
42.     lua_pushinteger(lu, 3);    
43. //获得栈中第一个元素(也就是刚刚放入的第一个元素“1”)  
44. int n = lua_tointeger(lu, 1);    
45. //获得栈中第二个元素  
46.     n = lua_tointeger(lu, 2);    
47. //获得栈中的元素总数(如果总数为0,表示空。前面放入两个,这里的值为2)  
48. int nStack = lua_gettop(lu);    
49. //剔除栈中元素(剔除两个,栈空)  
50.     lua_pop(lu, 2);    
51. //获得栈中元素总数  
52.     nStack = lua_gettop(lu);    
53.   
54. /*执行内存脚本*/  
55.   
56. //在lua脚本中,print函数是打印操作,print("Hello world")相当于打印一句Hello world。此时str相当于脚本中的打印操作  
57. "print (\"Hello world!\")";    
58. //把str加载到内存中,其中最后一个参数"name"是chunk名字,用于debug或者错误信息的标识  
59. "line");    
60. //调用函数。PS:lua_pcall的参数中n-nargs表示参数的个数,r-nresults表示...,errfunc表示  
61.     lua_pcall(lu, 0,0,0);    
62.     
63. /*加载脚本中定义的变量  */  
64. "../../luaScripts/test.lua");    
65. //压入aa名字(必须先压入需要取值的数据名,然后通过取值函数(例如tointeger) 从栈中取值)  
66. "aa");    
67. //压入bb名字  
68. "bb");    
69. //前面已经演示过传入正数索引调用tointeger,现在演示如果传入的参数为负数,则会从后开始取值  
70. int bb = lua_tointeger(lu, -1);    
71. int aa = lua_tointeger(lu, -2);    
72.         
73. /*执行脚本中定义的无参函数  */  
74. //压入hello函数名字,其实无论函数还是变量,都是通过压入名字然后去调用的。  
75. "hello");    
76. //参数nargs为0,表示调用的是无参的函数  
77.     nret = lua_pcall(lu, 0,0,0);    
78.         
79. /*执行脚本中定义的有参函数  */  
80. "fadd");    
81. //压入即将作为参数的对象  
82.     lua_pushnumber(lu, aa);    
83.     lua_pushnumber(lu, bb);    
84. //调用函数并获得返回结果(如果nret为0,表示调用成功,返回值会放入栈,通过取值即可获得。否则失败,失败时lua会产生失败信息放入栈,通过取值就可以获得错误信息)  
85.     nret = lua_pcall(lu, 2,1,0);    
86.     
87.   
88. "1 元素总数:" << lua_gettop(lu) << endl;  
89. if (nret != 0)    
90.     {    
91. //打印错误信息  
92. const char *pc = lua_tostring(lu, -1);    
93.         cout << pc;    
94.   
95. "2 元素总数:" << lua_gettop(lu) << endl;  
96.     }    
97. else    
98.     {    
99. //打印结果  
100.         nret = lua_tointeger(lu, -1);    
101. "调用脚本函数:" << endl;    
102. " + " << bb << " = " << nret << endl;    
103.   
104. "3 元素总数:" << lua_gettop(lu) << endl;  
105. //?  
106.         lua_pop(lu, 1);    
107. "4 元素总数:" << lua_gettop(lu) << endl;  
108.     }    
109.     
110. /*脚本中调用C++函数*/  
111. //压入c++函数  
112.     lua_pushcfunction(lu, fcAdd);    
113. //取出fcAdd函数使用  
114. "fcAdd");    
115. //压入脚本函数  
116. "fc");    
117. //压入参数  
118.     lua_pushnumber(lu, aa);    
119.     lua_pushnumber(lu, bb);    
120. //调用函数  
121.     nret = lua_pcall(lu, 2,1,0);    
122.     
123. if (nret != 0)    
124.     {    
125. const char *pc = lua_tostring(lu, -1);    
126.         cout << pc;    
127.     }    
128. else    
129.     {    
130.         nret = lua_tointeger(lu, -1);    
131. "调用C++函数:" << endl;    
132. " + " << bb << " = " << nret << endl;    
133.         lua_pop(lu, 1);    
134.     }    
135.         
136.     lua_close(lu);    
137. "pause");    
138. return 0;    
139. }


(代码参考如下博客:,我只是做了更详细的说明和使用体验,部分言语可能不当,因为此时我还是个初学者。)


6.lua脚本的创建

lua脚本其实就是个文本文件,之后后缀名改为lua了,例如第五步的test.lua脚本,这里列出test.lua脚本的源码


[cpp] view plaincopy


1. aa=2;    
2. bb=3;    
3. function hello(a,b)    
4. "Hello in script!")    
5. end    
6. function fadd(a,b)    
7. return a+b    
8. end    
9. function fc(a,b)    
10. return fcAdd(a,b)    
11. end