- 浏览: 182161 次
- 性别:
- 来自: 杭州
文章分类
- 全部博客 (95)
- Linux开发 (13)
- 多线程并行 (1)
- linux工具使用 (11)
- linux网络编程 (1)
- 开发环境 (2)
- 系统内核分析 (0)
- 网络编程 (7)
- 性能优化 (2)
- 多线程编程 (2)
- 智能指针 (1)
- C++技巧 (3)
- Linux调试 (4)
- 分布式系统 (3)
- TCP/IP协议 (4)
- linux内核,操作系统 (2)
- 内存数据库 (2)
- git hub (1)
- pthread; linux 多线程 (1)
- protobuf (1)
- hash算法 (1)
- python小工具 (1)
- lua (1)
- OTL DB (2)
- 硬件原理 (1)
- mysql (3)
- mysql索引 B树 (1)
- HTTP (1)
- Memcached 一致性hash (1)
- memcached (1)
- make (1)
- mysql批量操作 (1)
- linux系统优化 (1)
- oracle (1)
- Zookeeper (3)
- java开发 (19)
- tigase (3)
- 运维 (1)
- 字符编码 (1)
最新评论
转自:http://blog.csdn.net/dingdingko/article/details/7208744
使用LUA的目的:
当你真正要在项目中使用LUA时会明白自己的选择:
为了程序的可扩展性和随意性,减少后期需求的变化进项目造成的影响.
本文只介绍一些很肤浅关于LUA的C环境构建,及一些简单的LUA函数应用,是自己使用LUA的总结和入门记录.
LUA将给程序带来的功能:
1.LUA可以当一个配置文件使用(读写LUA全局变量)
2.程序中调用LUA定义的函数(C函数调用lua)
3.LUA可以调用自定义的C函数 (lua调用C函数)
4.运行LUA文件的函数(调用LUA文件运行函数)
5.运行LUA函数的函数(调用LUA代码片断的函数)
以上是LUA的一些基本应用,也是一个构建LUA的C环境必须实现的基本功能,主要是C程序和LUA的几个交互.下面会一一介绍,对于LUA的构架还是很必要的
LUA的总体认识:
头文件lua.h定义了Lua提供的基础函数。其中包括创建一个新的Lua环境的函数(如lua_open),调用Lua函数(如lua_pcall)的函数,读取/写入Lua环境的全局变量的函数,注册可以被Lua代码调用的新函数的函数,等等。所有在lua.h中被定义的都有一个lua_前缀。
头文件lauxlib.h定义了辅助库(auxlib)提供的函数。同样,所有在其中定义的函数等都以luaL_打头(例如,luaL_loadbuffer)。辅助库利用lua.h中提供的基础函数提供了更高层次上的抽象;所有Lua标准库都使用了auxlib。
构建一个最简单的LUA运行环境:
////////////////////构建LUA的基本运行环境
#include <stdio.h>
///使用C调用(不使用的话会有问题)
extern "C" {
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
}
#include <string>
int main (void)
{
char buff[256];
int error;
//LUA库的初始化
lua_State *L = lua_open(); /* opens Lua */
luaopen_base(L); /* opens the basic library */
luaopen_table(L); /* opens the table library */
luaopen_io(L); /* opens the I/O library */
luaopen_string(L); /* opens the string lib. */
luaopen_math(L); /* opens the math lib. */
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);/* pop error message from the stack */+
}
}
lua_close(L);
return 0;
}
LUA堆栈原理:
当在Lua和C之间交换数据时我们面临着两个问题:动态与静态类型系统的不匹配和自动与手动内存管理的不一致。
用一个抽象的栈在Lua与C之间交换值。栈中的每一条记录都可以保存任何Lua值。无论你何时想要从Lua请求一个值(比如一个全局变量的值),调用Lua,被请求的值将会被压入栈。无论你何时想要传递一个值给Lua,首先将这个值压入栈,然后调用Lua(这个值将被弹出)。我们仍然需要一个不同的函数将每种C类型压入栈和一个不同函数从栈上取值(译注:只是取出不是弹出),但是我们避免了组合式的爆炸(combinatorial explosion)。另外,因为栈是由Lua来管理的,垃圾回收器知道那个值正在被C使用。几乎所有的API函数都用到了栈。正如我们在第一个例子中所看到的,luaL_loadbuffer把它的结果留在了栈上(被编译的chunk或一条错误信息);lua_pcall从栈上获取要被调用的函数并把任何临时的错误信息放在这里。
当Lua在起始以及在Lua调用C的时候,栈上至少有20个空闲的记录(lua.h中的LUA_MINSTACK宏定义了这个常量)
LUA基本函数介绍:
压入栈函数:
void lua_pushnil (lua_State *L);
void lua_pushboolean (lua_State *L, int bool);
void lua_pushnumber (lua_State *L, double n);
//Lua中的字符串不是以零为结束符的;Lua从来不保持一个指向外部字符串的指针
void lua_pushlstring (lua_State *L, const char *s, size_t length);
void lua_pushstring (lua_State *L, const char *s);
//同样也有将C函数和userdata值压入栈的函数.
int lua_checkstack (lua_State *L, int sz);
查询元素
API用索引来访问栈中的元素。在栈中的第一个元素(也就是第一个被压入栈的)有索引1,下一个有索引2,以此类推。
API提供了一套lua_is*函数来检查一个元素是否是一个指定的类型
int lua_is... (lua_State *L, int index);
如:lua_isnumber,lua_isstring,lua_istable
还有一个lua_type函数,它返回栈中元素的类型。(lua_is*中的有些函数实际上是用了这个函数定义的宏)在lua.h头文件中,每种类型都被定义为一个常量:LUA_TNIL、LUA_TBOOLEAN、LUA_TNUMBER、LUA_TSTRING、LUA_TTABLE、LUA_TFUNCTION、LUA_TUSERDATA以及LUA_TTHREAD。这个函数主要被用在与一个switch语句联合使用。当我们需要真正的检查字符串和数字类型时它也是有用的.
为了从栈中获得值,这里有lua_to*函数:
int lua_toboolean (lua_State *L, int index);
double lua_tonumber (lua_State *L, int index);
//Lua_tostring函数返回一个指向字符串的内部拷贝的指针
const char * lua_tostring (lua_State *L, int index);
size_t lua_strlen (lua_State *L, int index);
其他堆栈操作:
除开上面所提及的C与堆栈交换值的函数外,API也提供了下列函数来完成通常的堆栈维护工作:
//返回堆栈中的元素个数,它也是栈顶元素的索引
int lua_gettop (lua_State *L);
//lua_settop设置栈顶(也就是堆栈中的元素个数)为一个指定的值,lua_settop(L,0)清空堆栈
void lua_settop (lua_State *L, int index);
//压入堆栈上指定索引的一个抟贝到栈顶
void lua_pushvalue (lua_State *L, int index);
//移除指定索引位置的元素
void lua_remove (lua_State *L, int index);
//移动栈顶元素到指定索引的位置
void lua_insert (lua_State *L, int index);
//从栈顶弹出元素值并将其设置到指定索引位置
void lua_replace (lua_State *L, int index);
//测试代码,返回lua的类型
static void stackDump (lua_State *L)
{
int i;
int top = lua_gettop(L);
for (i = 1; i <= top; i++)
{ /* repeat for each level */
int t = lua_type(L, i);
switch (t)
{
case LUA_TSTRING: /* strings */
printf("`%s'", lua_tostring(L, i));
break;
case LUA_TBOOLEAN: /* booleans */
printf(lua_toboolean(L, i) ? "true" : "false");
break;
case LUA_TNUMBER: /* numbers */
printf("%g", lua_tonumber(L, i));
break;
default: /* other values */
printf("%s", lua_typename(L, t));
break;
}
printf(" "); /* put a separator */
}
printf("\n"); /* end the listing */
}
int main (void)
{
lua_State *L = lua_open();
lua_pushboolean(L, 1); lua_pushnumber(L, 10);
lua_pushnil(L); lua_pushstring(L, "hello");
stackDump(L);
/* true 10 nil `hello' */
lua_pushvalue(L, -4); stackDump(L);
/* true 10 nil `hello' true */
lua_replace(L, 3); stackDump(L);
/* true 10 true `hello' */
lua_settop(L, 6); stackDump(L);
/* true 10 true `hello' nil nil */
lua_remove(L, -3); stackDump(L);
/* true 10 true nil nil */
lua_settop(L, -5); stackDump(L);
/* true */
lua_close(L);
return 0;
}
错误处理
Lua中的所有结构都是动态的:它们按需增长,最终当可能时又会缩减。意味着内存分配失败的可能性在Lua中是普遍的。几乎任意操作都会面对这种意外。Lua的API中用异常发出这些错误而不是为每步操作产生错误码。这意味着所有的API函数可能抛出一个错误(也就是调用longjmp)来代替返回。
你可以使用lua_atpanic函数设置你自己的panic函数
不是所有的API函数都会抛出异常,lua_open、lua_close、lua_pcall和lua_load都是安全的
下面将介绍LUA中真正会常用到的几个方法(LUA将给程序带来的功能所提到的)
1.LUA可以当一个配置文件使用(读写LUA全局变量)
lua配置文件:
width=100
height=200
读取配置文件程序:
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
void load (char *filename, int *width, int *height)
{
lua_State *L = lua_open();
luaopen_base(L);
// luaopen_io(L);
luaopen_string(L);
luaopen_math(L);
if (luaL_loadfile(L, filename) || lua_pcall(L, 0, 0, 0))
{//读取LUA的配置文件
printf("cannot run configuration file: %s", lua_tostring(L, -1));
}
//得到相应的配置文件内容
lua_getglobal(L, "width");
lua_getglobal(L, "height");
if (!lua_isnumber(L, -2))
{
printf("`width' should be a number\n");
}
if (!lua_isnumber(L, -1))
{
printf("`height' should be a number\n");
}
*width = (int)lua_tonumber(L, -2);
*height = (int)lua_tonumber(L, -1);
lua_close(L);
}
读取配置文件中的TABLE数据
lua 配置内容 :
background = {r=0.30, g=0.10, b=0}
程序:
int GetField(lua_State* L, const char* key)
{
int result;
lua_pushstring(L, key); //把要得到的值压入
lua_gettable(L, -2); //他接受table在栈中的位置为参数,将对应key值出栈
if (!lua_isnumber(L, -1))
{
printf("invalid component in background color");
}
result = (int)lua_tonumber(L, -1);
lua_pop(L, 1); /* remove number */
return result;
}
//从lua中得到table的数据
//RED = {r=255, g=0, b=0}
//GRE = {r=0, g=255, b=0}
//BLU = {r=0, g=0, b=255}
void GetTableInfo(char *filename, const char* szTableName)
{
lua_State *L = lua_open();
luaopen_base(L);
luaopen_string(L);
luaopen_math(L);
if (luaL_loadfile(L, filename) || lua_pcall(L, 0, 0, 0))
{
printf("cannot run configuration file: %s", lua_tostring(L, -1));
}
lua_getglobal(L, szTableName); //得到table的全局变量
if (!lua_istable(L, -1))
{
printf("`width' should be a number\n");
}
int Red = GetField(L, "r"); //得到Table中的r值
int Gre = GetField(L, "g");
int Blu = GetField(L, "b");
printf("%d,%d,%d",Red, Gre, Blu);
lua_close(L);
}
2.程序中调用LUA定义的函数(C函数调用lua)
程序中调用LUA定义的函数
使用API调用函数的方法是很简单的:
首先,将被调用的函数入栈;
第二,依次将所有参数入栈;
第三,使用lua_pcall调用函数;
最后,从栈中获取函数执行返回的结果。
lua函数
function f (x, y)
return (x^2 * math.sin(y))/(1 - x)
end
//在C中对于给定的x,y计算z=f(x,y)的值
/* call a function `f' defined in Lua */
double f (double x, double y)
{
double z;
/* push functions and arguments */
lua_getglobal(L, "f"); /* function to be called */
lua_pushnumber(L, x); /* push 1st argument */
lua_pushnumber(L, y); /* push 2nd argument */
/* do the call (2 arguments, 1 result) */
if (lua_pcall(L, 2, 1, 0) != 0) //。第四个参数可以指定一个错误处理函数
error(L, "error running function `f': %s", lua_tostring(L, -1));
/* retrieve result */
if (!lua_isnumber(L, -1))
error(L, "function `f' must return a number");
z = lua_tonumber(L, -1);
lua_pop(L, 1); /* pop returned value */
return z;
}
在将结果入栈之前,lua_pcall会将栈内的函数和参数移除。如果函数返回多个结果,第一个结果被第一个入栈,因此如果有n个返回结果,第一个返回结果在栈中的位置为-n,最后一个返回结果在栈中的位置为-1。
lua_pcall返回三个LUA_ERRRUN LUA_ERRMEM LUA_ERRER
我们的封装后的函数(call_va)接受被调用的函数明作为第一个参数,第二参数是一个描述参数和结果类型的字符串,最后是一个保存返回结果的变量指针的列表。使用这个函数,我们可以将前面的例子改写为:
call_va("f", "dd>d", x, y, &z); 与lua_pcall有相同的意思
字符串 "dd>d" 表示函数有两个double类型的参数,一个double类型的返回结果。我们使用字母 'd' 表示double;'i' 表示integer,'s' 表示strings;'>' 作为参数和结果的分隔符。如果函数没有返回结果,'>' 是可选的。
void call_va (lua_State *L, const char *func, const char *sig, ...)
{
va_list vl;
int iParamCnt = 0;//参数个数
int iRetCnt = 0;//返回值什数
va_start(vl, sig);
lua_getglobal(L, func); /* get function */
/* push arguments */
bool bRet = false;
while (*sig)
{ /* push arguments */
switch (*sig)
{
case 'd': /* double argument */
lua_pushnumber(L, va_arg(vl, double));
break;
case 'i': /* int argument */
lua_pushnumber(L, va_arg(vl, int));
break;
case 's': /* string argument */
lua_pushstring(L, va_arg(vl, char *));
break;
case '>':
iParamCnt = iParamCnt - 1;
bRet = true;
break;
default:
printf("invalid option (%c)", *(sig - 1));
}
iParamCnt = iParamCnt + 1;
*sig++;
if (bRet)
{
break;
}
luaL_checkstack(L, 1, "too many arguments");
}/* endwhile:*/
/* do the call */
iRetCnt = strlen(sig); /* number of expected results */
if (lua_pcall(L, iParamCnt, iRetCnt, 0) != 0) /* do the call */
{
printf("error running function `%s': %s", func, lua_tostring(L, -1));
}
/* retrieve results */
iRetCnt = - iRetCnt; /* stack index of first result */
while (*sig)
{ /* get results */
switch (*sig)
{
case 'd': /* double result */
{
if (!lua_isnumber(L, iRetCnt))
{
printf("wrong result type");
}
*va_arg(vl, double *) = lua_tonumber(L, iRetCnt);
}
break;
case 'i': /* int result */
if (!lua_isnumber(L, iRetCnt))
printf("wrong result type");
*va_arg(vl, int *) = (int)lua_tonumber(L, iRetCnt);
break;
case 's': /* string result */
if (!lua_isstring(L, iRetCnt))
printf("wrong result type");
*va_arg(vl, const char **) = lua_tostring(L, iRetCnt);
break;
default:
printf("invalid option (%c)", *(sig - 1));
}
iRetCnt++;
*sig++;
}
va_end(vl);
}
3.LUA可以调用自定义的C函数 (lua调用C函数)
在本节中我会介绍如何提供C函数给LUA在.lua文件中调用
这儿有一个重要的概念:用来交互的栈不是全局变量,每一个函数都有他自己的私有栈
当Lua调用C函数的时候,第一个参数总是在这个私有栈的index=1的位置
函数注册到LUA中
任何在Lua中注册的函数必须有同样的原型,这个原型声明定义就是lua.h中的lua_CFunction:
typedef int (*lua_CFunction) (lua_State *L);
static int l_sin (lua_State *L)
{
double d = lua_tonumber(L, 1); /* get argument */
lua_pushnumber(L, sin(d)); /* push result */
return 1; /* number of results */
}
还必须首先注册这个函数。我们使用lua_pushcfunction来完成这个任务
lua_pushcfunction(l, l_sin); //将类型为function的值入栈,
lua_setglobal(l, "mysin"); //将function赋值给全局变量mysin
static int l_sin (lua_State *L)
{
double d = luaL_checknumber(L, 1);
lua_pushnumber(L, sin(d));
return 1; /* number of results */
}
static int l_dir (lua_State *L)
{
DIR *dir;
struct dirent *entry;
int i;
const char *path = luaL_checkstring(L, 1);//函数用来检测参数是否为字符
/* open directory */
dir = opendir(path);
if (dir == NULL)
{ /* error opening the directory? */
lua_pushnil(L); /* return nil and ... */
lua_pushstring(L, strerror(errno)); /* error message */
return 2; /* number of results */
}
/* create result table */
lua_newtable(L);
i = 1;
while ((entry = readdir(dir)) != NULL)
{
lua_pushnumber(L, i++); /* push key */
lua_pushstring(L, entry->d_name); /* push value */
lua_settable(L, -3);
}
closedir(dir);
return 1; /* table is already on top */
}
#lua_settable(lua_State* L, int index)
#就是把表在lua堆栈中的值弹出来,index 是table 在堆栈中的位置,假如 table 在 -3, 则#key 应该是 -2,value 是 -1
一个Lua库实际上是一个定义了一系列Lua函数的chunk,并将这些函数保存在适当的地方,通常作为table的域来保存Lua的C库就是这样实现的。除了定义C函数之外,还必须定义一个特殊的用来和Lua库的主chunk通信的特殊函数一旦调用,这个函数就会注册库中所有的C函数,并将他们保存到适当的位置。
4.运行LUA文件的函数(调用LUA文件运行函数)
lua_State* m_pLuaState = lua_open();
luaL_openlibs(m_pLuaState);
if(luaL_dofile(m_pLuaState, strLuaFilePath.c_str()))
{//直接运行lua中独立的函数
return false;
}
return true;
5.运行LUA函数的函数(调用LUA代码片断的函数)
1. 选注册必要的C函数(直接调用非C的lua函数也行: 3.LUA可以调用自定义的C函数)
2. 把注册的函数写入LUA
3. 运行LUA函数的函数
//开放给doluafunc使用的函数,autoluafunc_XXXX
char szTemp[256] = {0};
_snprintf_s(szTemp, sizeof(szTemp), "function autoluafunc_%s()\n %s();\n end\n",函数名, 函数名);
luaL_dostring(m_pLuaState, szTemp);//放入LUA调用表中
char szTemp[256] = {0};
_snprintf_s(szTemp, sizeof(szTemp), "autoluafunc_%s",函数名);
lua_getglobal(m_pLuaState, szTemp);
int ret = lua_pcall(m_pLuaState, 0, 0, 0);
由以上代码看来运行LUA函数的函数都是无参数的LUA
看上去没有什么用的代码段却在ini配置等方面有很好的应用,如ini中配置一串lua函数,你可以把这一串lua函数用一个特定的无参lua重新定义一遍,然后使用此lua调用,具体的过程还要通过项目实践才会了解~
使用LUA的目的:
当你真正要在项目中使用LUA时会明白自己的选择:
为了程序的可扩展性和随意性,减少后期需求的变化进项目造成的影响.
本文只介绍一些很肤浅关于LUA的C环境构建,及一些简单的LUA函数应用,是自己使用LUA的总结和入门记录.
LUA将给程序带来的功能:
1.LUA可以当一个配置文件使用(读写LUA全局变量)
2.程序中调用LUA定义的函数(C函数调用lua)
3.LUA可以调用自定义的C函数 (lua调用C函数)
4.运行LUA文件的函数(调用LUA文件运行函数)
5.运行LUA函数的函数(调用LUA代码片断的函数)
以上是LUA的一些基本应用,也是一个构建LUA的C环境必须实现的基本功能,主要是C程序和LUA的几个交互.下面会一一介绍,对于LUA的构架还是很必要的
LUA的总体认识:
头文件lua.h定义了Lua提供的基础函数。其中包括创建一个新的Lua环境的函数(如lua_open),调用Lua函数(如lua_pcall)的函数,读取/写入Lua环境的全局变量的函数,注册可以被Lua代码调用的新函数的函数,等等。所有在lua.h中被定义的都有一个lua_前缀。
头文件lauxlib.h定义了辅助库(auxlib)提供的函数。同样,所有在其中定义的函数等都以luaL_打头(例如,luaL_loadbuffer)。辅助库利用lua.h中提供的基础函数提供了更高层次上的抽象;所有Lua标准库都使用了auxlib。
构建一个最简单的LUA运行环境:
////////////////////构建LUA的基本运行环境
#include <stdio.h>
///使用C调用(不使用的话会有问题)
extern "C" {
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
}
#include <string>
int main (void)
{
char buff[256];
int error;
//LUA库的初始化
lua_State *L = lua_open(); /* opens Lua */
luaopen_base(L); /* opens the basic library */
luaopen_table(L); /* opens the table library */
luaopen_io(L); /* opens the I/O library */
luaopen_string(L); /* opens the string lib. */
luaopen_math(L); /* opens the math lib. */
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);/* pop error message from the stack */+
}
}
lua_close(L);
return 0;
}
LUA堆栈原理:
当在Lua和C之间交换数据时我们面临着两个问题:动态与静态类型系统的不匹配和自动与手动内存管理的不一致。
用一个抽象的栈在Lua与C之间交换值。栈中的每一条记录都可以保存任何Lua值。无论你何时想要从Lua请求一个值(比如一个全局变量的值),调用Lua,被请求的值将会被压入栈。无论你何时想要传递一个值给Lua,首先将这个值压入栈,然后调用Lua(这个值将被弹出)。我们仍然需要一个不同的函数将每种C类型压入栈和一个不同函数从栈上取值(译注:只是取出不是弹出),但是我们避免了组合式的爆炸(combinatorial explosion)。另外,因为栈是由Lua来管理的,垃圾回收器知道那个值正在被C使用。几乎所有的API函数都用到了栈。正如我们在第一个例子中所看到的,luaL_loadbuffer把它的结果留在了栈上(被编译的chunk或一条错误信息);lua_pcall从栈上获取要被调用的函数并把任何临时的错误信息放在这里。
当Lua在起始以及在Lua调用C的时候,栈上至少有20个空闲的记录(lua.h中的LUA_MINSTACK宏定义了这个常量)
LUA基本函数介绍:
压入栈函数:
void lua_pushnil (lua_State *L);
void lua_pushboolean (lua_State *L, int bool);
void lua_pushnumber (lua_State *L, double n);
//Lua中的字符串不是以零为结束符的;Lua从来不保持一个指向外部字符串的指针
void lua_pushlstring (lua_State *L, const char *s, size_t length);
void lua_pushstring (lua_State *L, const char *s);
//同样也有将C函数和userdata值压入栈的函数.
int lua_checkstack (lua_State *L, int sz);
查询元素
API用索引来访问栈中的元素。在栈中的第一个元素(也就是第一个被压入栈的)有索引1,下一个有索引2,以此类推。
API提供了一套lua_is*函数来检查一个元素是否是一个指定的类型
int lua_is... (lua_State *L, int index);
如:lua_isnumber,lua_isstring,lua_istable
还有一个lua_type函数,它返回栈中元素的类型。(lua_is*中的有些函数实际上是用了这个函数定义的宏)在lua.h头文件中,每种类型都被定义为一个常量:LUA_TNIL、LUA_TBOOLEAN、LUA_TNUMBER、LUA_TSTRING、LUA_TTABLE、LUA_TFUNCTION、LUA_TUSERDATA以及LUA_TTHREAD。这个函数主要被用在与一个switch语句联合使用。当我们需要真正的检查字符串和数字类型时它也是有用的.
为了从栈中获得值,这里有lua_to*函数:
int lua_toboolean (lua_State *L, int index);
double lua_tonumber (lua_State *L, int index);
//Lua_tostring函数返回一个指向字符串的内部拷贝的指针
const char * lua_tostring (lua_State *L, int index);
size_t lua_strlen (lua_State *L, int index);
其他堆栈操作:
除开上面所提及的C与堆栈交换值的函数外,API也提供了下列函数来完成通常的堆栈维护工作:
//返回堆栈中的元素个数,它也是栈顶元素的索引
int lua_gettop (lua_State *L);
//lua_settop设置栈顶(也就是堆栈中的元素个数)为一个指定的值,lua_settop(L,0)清空堆栈
void lua_settop (lua_State *L, int index);
//压入堆栈上指定索引的一个抟贝到栈顶
void lua_pushvalue (lua_State *L, int index);
//移除指定索引位置的元素
void lua_remove (lua_State *L, int index);
//移动栈顶元素到指定索引的位置
void lua_insert (lua_State *L, int index);
//从栈顶弹出元素值并将其设置到指定索引位置
void lua_replace (lua_State *L, int index);
//测试代码,返回lua的类型
static void stackDump (lua_State *L)
{
int i;
int top = lua_gettop(L);
for (i = 1; i <= top; i++)
{ /* repeat for each level */
int t = lua_type(L, i);
switch (t)
{
case LUA_TSTRING: /* strings */
printf("`%s'", lua_tostring(L, i));
break;
case LUA_TBOOLEAN: /* booleans */
printf(lua_toboolean(L, i) ? "true" : "false");
break;
case LUA_TNUMBER: /* numbers */
printf("%g", lua_tonumber(L, i));
break;
default: /* other values */
printf("%s", lua_typename(L, t));
break;
}
printf(" "); /* put a separator */
}
printf("\n"); /* end the listing */
}
int main (void)
{
lua_State *L = lua_open();
lua_pushboolean(L, 1); lua_pushnumber(L, 10);
lua_pushnil(L); lua_pushstring(L, "hello");
stackDump(L);
/* true 10 nil `hello' */
lua_pushvalue(L, -4); stackDump(L);
/* true 10 nil `hello' true */
lua_replace(L, 3); stackDump(L);
/* true 10 true `hello' */
lua_settop(L, 6); stackDump(L);
/* true 10 true `hello' nil nil */
lua_remove(L, -3); stackDump(L);
/* true 10 true nil nil */
lua_settop(L, -5); stackDump(L);
/* true */
lua_close(L);
return 0;
}
错误处理
Lua中的所有结构都是动态的:它们按需增长,最终当可能时又会缩减。意味着内存分配失败的可能性在Lua中是普遍的。几乎任意操作都会面对这种意外。Lua的API中用异常发出这些错误而不是为每步操作产生错误码。这意味着所有的API函数可能抛出一个错误(也就是调用longjmp)来代替返回。
你可以使用lua_atpanic函数设置你自己的panic函数
不是所有的API函数都会抛出异常,lua_open、lua_close、lua_pcall和lua_load都是安全的
下面将介绍LUA中真正会常用到的几个方法(LUA将给程序带来的功能所提到的)
1.LUA可以当一个配置文件使用(读写LUA全局变量)
lua配置文件:
width=100
height=200
读取配置文件程序:
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
void load (char *filename, int *width, int *height)
{
lua_State *L = lua_open();
luaopen_base(L);
// luaopen_io(L);
luaopen_string(L);
luaopen_math(L);
if (luaL_loadfile(L, filename) || lua_pcall(L, 0, 0, 0))
{//读取LUA的配置文件
printf("cannot run configuration file: %s", lua_tostring(L, -1));
}
//得到相应的配置文件内容
lua_getglobal(L, "width");
lua_getglobal(L, "height");
if (!lua_isnumber(L, -2))
{
printf("`width' should be a number\n");
}
if (!lua_isnumber(L, -1))
{
printf("`height' should be a number\n");
}
*width = (int)lua_tonumber(L, -2);
*height = (int)lua_tonumber(L, -1);
lua_close(L);
}
读取配置文件中的TABLE数据
lua 配置内容 :
background = {r=0.30, g=0.10, b=0}
程序:
int GetField(lua_State* L, const char* key)
{
int result;
lua_pushstring(L, key); //把要得到的值压入
lua_gettable(L, -2); //他接受table在栈中的位置为参数,将对应key值出栈
if (!lua_isnumber(L, -1))
{
printf("invalid component in background color");
}
result = (int)lua_tonumber(L, -1);
lua_pop(L, 1); /* remove number */
return result;
}
//从lua中得到table的数据
//RED = {r=255, g=0, b=0}
//GRE = {r=0, g=255, b=0}
//BLU = {r=0, g=0, b=255}
void GetTableInfo(char *filename, const char* szTableName)
{
lua_State *L = lua_open();
luaopen_base(L);
luaopen_string(L);
luaopen_math(L);
if (luaL_loadfile(L, filename) || lua_pcall(L, 0, 0, 0))
{
printf("cannot run configuration file: %s", lua_tostring(L, -1));
}
lua_getglobal(L, szTableName); //得到table的全局变量
if (!lua_istable(L, -1))
{
printf("`width' should be a number\n");
}
int Red = GetField(L, "r"); //得到Table中的r值
int Gre = GetField(L, "g");
int Blu = GetField(L, "b");
printf("%d,%d,%d",Red, Gre, Blu);
lua_close(L);
}
2.程序中调用LUA定义的函数(C函数调用lua)
程序中调用LUA定义的函数
使用API调用函数的方法是很简单的:
首先,将被调用的函数入栈;
第二,依次将所有参数入栈;
第三,使用lua_pcall调用函数;
最后,从栈中获取函数执行返回的结果。
lua函数
function f (x, y)
return (x^2 * math.sin(y))/(1 - x)
end
//在C中对于给定的x,y计算z=f(x,y)的值
/* call a function `f' defined in Lua */
double f (double x, double y)
{
double z;
/* push functions and arguments */
lua_getglobal(L, "f"); /* function to be called */
lua_pushnumber(L, x); /* push 1st argument */
lua_pushnumber(L, y); /* push 2nd argument */
/* do the call (2 arguments, 1 result) */
if (lua_pcall(L, 2, 1, 0) != 0) //。第四个参数可以指定一个错误处理函数
error(L, "error running function `f': %s", lua_tostring(L, -1));
/* retrieve result */
if (!lua_isnumber(L, -1))
error(L, "function `f' must return a number");
z = lua_tonumber(L, -1);
lua_pop(L, 1); /* pop returned value */
return z;
}
在将结果入栈之前,lua_pcall会将栈内的函数和参数移除。如果函数返回多个结果,第一个结果被第一个入栈,因此如果有n个返回结果,第一个返回结果在栈中的位置为-n,最后一个返回结果在栈中的位置为-1。
lua_pcall返回三个LUA_ERRRUN LUA_ERRMEM LUA_ERRER
我们的封装后的函数(call_va)接受被调用的函数明作为第一个参数,第二参数是一个描述参数和结果类型的字符串,最后是一个保存返回结果的变量指针的列表。使用这个函数,我们可以将前面的例子改写为:
call_va("f", "dd>d", x, y, &z); 与lua_pcall有相同的意思
字符串 "dd>d" 表示函数有两个double类型的参数,一个double类型的返回结果。我们使用字母 'd' 表示double;'i' 表示integer,'s' 表示strings;'>' 作为参数和结果的分隔符。如果函数没有返回结果,'>' 是可选的。
void call_va (lua_State *L, const char *func, const char *sig, ...)
{
va_list vl;
int iParamCnt = 0;//参数个数
int iRetCnt = 0;//返回值什数
va_start(vl, sig);
lua_getglobal(L, func); /* get function */
/* push arguments */
bool bRet = false;
while (*sig)
{ /* push arguments */
switch (*sig)
{
case 'd': /* double argument */
lua_pushnumber(L, va_arg(vl, double));
break;
case 'i': /* int argument */
lua_pushnumber(L, va_arg(vl, int));
break;
case 's': /* string argument */
lua_pushstring(L, va_arg(vl, char *));
break;
case '>':
iParamCnt = iParamCnt - 1;
bRet = true;
break;
default:
printf("invalid option (%c)", *(sig - 1));
}
iParamCnt = iParamCnt + 1;
*sig++;
if (bRet)
{
break;
}
luaL_checkstack(L, 1, "too many arguments");
}/* endwhile:*/
/* do the call */
iRetCnt = strlen(sig); /* number of expected results */
if (lua_pcall(L, iParamCnt, iRetCnt, 0) != 0) /* do the call */
{
printf("error running function `%s': %s", func, lua_tostring(L, -1));
}
/* retrieve results */
iRetCnt = - iRetCnt; /* stack index of first result */
while (*sig)
{ /* get results */
switch (*sig)
{
case 'd': /* double result */
{
if (!lua_isnumber(L, iRetCnt))
{
printf("wrong result type");
}
*va_arg(vl, double *) = lua_tonumber(L, iRetCnt);
}
break;
case 'i': /* int result */
if (!lua_isnumber(L, iRetCnt))
printf("wrong result type");
*va_arg(vl, int *) = (int)lua_tonumber(L, iRetCnt);
break;
case 's': /* string result */
if (!lua_isstring(L, iRetCnt))
printf("wrong result type");
*va_arg(vl, const char **) = lua_tostring(L, iRetCnt);
break;
default:
printf("invalid option (%c)", *(sig - 1));
}
iRetCnt++;
*sig++;
}
va_end(vl);
}
3.LUA可以调用自定义的C函数 (lua调用C函数)
在本节中我会介绍如何提供C函数给LUA在.lua文件中调用
这儿有一个重要的概念:用来交互的栈不是全局变量,每一个函数都有他自己的私有栈
当Lua调用C函数的时候,第一个参数总是在这个私有栈的index=1的位置
函数注册到LUA中
任何在Lua中注册的函数必须有同样的原型,这个原型声明定义就是lua.h中的lua_CFunction:
typedef int (*lua_CFunction) (lua_State *L);
static int l_sin (lua_State *L)
{
double d = lua_tonumber(L, 1); /* get argument */
lua_pushnumber(L, sin(d)); /* push result */
return 1; /* number of results */
}
还必须首先注册这个函数。我们使用lua_pushcfunction来完成这个任务
lua_pushcfunction(l, l_sin); //将类型为function的值入栈,
lua_setglobal(l, "mysin"); //将function赋值给全局变量mysin
static int l_sin (lua_State *L)
{
double d = luaL_checknumber(L, 1);
lua_pushnumber(L, sin(d));
return 1; /* number of results */
}
static int l_dir (lua_State *L)
{
DIR *dir;
struct dirent *entry;
int i;
const char *path = luaL_checkstring(L, 1);//函数用来检测参数是否为字符
/* open directory */
dir = opendir(path);
if (dir == NULL)
{ /* error opening the directory? */
lua_pushnil(L); /* return nil and ... */
lua_pushstring(L, strerror(errno)); /* error message */
return 2; /* number of results */
}
/* create result table */
lua_newtable(L);
i = 1;
while ((entry = readdir(dir)) != NULL)
{
lua_pushnumber(L, i++); /* push key */
lua_pushstring(L, entry->d_name); /* push value */
lua_settable(L, -3);
}
closedir(dir);
return 1; /* table is already on top */
}
#lua_settable(lua_State* L, int index)
#就是把表在lua堆栈中的值弹出来,index 是table 在堆栈中的位置,假如 table 在 -3, 则#key 应该是 -2,value 是 -1
一个Lua库实际上是一个定义了一系列Lua函数的chunk,并将这些函数保存在适当的地方,通常作为table的域来保存Lua的C库就是这样实现的。除了定义C函数之外,还必须定义一个特殊的用来和Lua库的主chunk通信的特殊函数一旦调用,这个函数就会注册库中所有的C函数,并将他们保存到适当的位置。
4.运行LUA文件的函数(调用LUA文件运行函数)
lua_State* m_pLuaState = lua_open();
luaL_openlibs(m_pLuaState);
if(luaL_dofile(m_pLuaState, strLuaFilePath.c_str()))
{//直接运行lua中独立的函数
return false;
}
return true;
5.运行LUA函数的函数(调用LUA代码片断的函数)
1. 选注册必要的C函数(直接调用非C的lua函数也行: 3.LUA可以调用自定义的C函数)
2. 把注册的函数写入LUA
3. 运行LUA函数的函数
//开放给doluafunc使用的函数,autoluafunc_XXXX
char szTemp[256] = {0};
_snprintf_s(szTemp, sizeof(szTemp), "function autoluafunc_%s()\n %s();\n end\n",函数名, 函数名);
luaL_dostring(m_pLuaState, szTemp);//放入LUA调用表中
char szTemp[256] = {0};
_snprintf_s(szTemp, sizeof(szTemp), "autoluafunc_%s",函数名);
lua_getglobal(m_pLuaState, szTemp);
int ret = lua_pcall(m_pLuaState, 0, 0, 0);
由以上代码看来运行LUA函数的函数都是无参数的LUA
看上去没有什么用的代码段却在ini配置等方面有很好的应用,如ini中配置一串lua函数,你可以把这一串lua函数用一个特定的无参lua重新定义一遍,然后使用此lua调用,具体的过程还要通过项目实践才会了解~
相关推荐
代码中还包含了一些注释掉的print语句,这些语句展示了unpack函数的使用方法。 ```lua a, b, c = returnMoreValues() ``` 上述代码执行后,变量a的值将会是1,变量b的值将会是2,变量c的值将会是3。紧接着,我们...
下面将详细介绍Luaiconv的使用方法、核心功能以及相关的编程技巧。 1. 安装与引入 首先,你需要下载luaiconv的源代码包,然后将其解压到你的Lua项目目录下。通常,luaiconv是一个单独的`.lua`文件,你可以通过`...
游戏公司可能使用自定义的加密方法来保护其lua脚本,防止被玩家篡改或获取敏感信息。而lua反编译工具则为逆向工程师提供了手段,让他们能探索游戏的内部逻辑,这对于mod制作、漏洞挖掘和游戏研究都有所帮助。 总之...
通过以上方法,你可以有效地在C++项目中集成Lua,利用Lua的灵活性编写可扩展的脚本,同时也能通过C++调用已有的功能,实现两者的无缝结合。在实际项目中,这可以极大地提高代码的可维护性和性能。
#### 一、Lua编程语言简介 - **定义与起源**:Lua是一种轻量级的脚本语言,由巴西的PUC里约大学开发。它被设计成小巧、快速,并且易于嵌入其他应用程序之中。 - **特点**: - **轻量级**:Lua的核心库非常小,可以...
在C++项目中集成Lua,通常需要使用一个名为"tolua++"或"luabind"的库,它们提供了将C++函数导出到Lua的机制。在这个实例中,C++工程可能已经包含了这样的库,并定义了一些可被Lua调用的函数。这些函数可以用来执行...
这些方法通常定义为静态方法,并使用LuaFunction注解标记。 4. 执行Lua脚本:通过LuaState的doFile()或doString()方法,可以加载并执行Lua脚本文件或字符串。 五、Android调用Lua 在Android应用中,你可以通过以下...
《Lua实例代码大全》是针对Lua编程语言的一份详尽实例集合,涵盖了多个核心库和扩展库的使用,包括luacurl(网络连接)、luafilesystem(文件系统操作)、luajson(JSON处理)、luasocket(网络套接字)、luasql...
### Lua API及Lua文档知识点概览 #### 一、引言 Lua是一种轻量级、高效且可嵌入的脚本语言,广泛应用于...以上内容覆盖了Lua语言的基础概念、高级特性以及标准库的使用方法,对于学习和使用Lua都是非常宝贵的知识点。
5. **加载和运行LUA脚本**:使用`luaL_loadfile()`或`luaL_dostring()`加载LUA脚本,并通过`lua_pcall()`执行脚本。记得处理可能出现的错误。 6. **处理LUA脚本的返回值**:LUA脚本的返回值可以通过`lua_type()`和`...
通过查看GitHub上的项目源码及使用示例(https://github.com/Lua-cURL/Lua-cURLv3),你可以深入了解Lua-cURL的完整功能和具体用法。这里不仅有详细的API文档,还有许多实际的例子,帮助你快速上手并解决实际问题。 ...
具体使用方法如下:首先在开始处调用socket.gettime()函数获取初始时间t0,然后执行你需要测量时间的代码段,在代码段之后再次调用socket.gettime()函数获取结束时间t1。最后,计算这两个时间点之间的差值t1-t0,就...
4. **数据类型转换**: Lua和C的数据类型不同,所以需要使用`lua_tonumber`、`lua_tostring`等函数将Lua值转换为C类型,反之亦然。 5. **错误处理**: 在C与Lua交互时,理解并处理错误至关重要。`lua_gettop`、`lua_...
在C#端,我们可以创建一个Lua实例,加载lua51.dll和LuaInterface.dll库,然后通过Lua对象的DoFile或DoString方法执行Lua脚本。例如: ```csharp using LuaInterface; // 创建Lua环境 Lua lua = new Lua(); lua....
2. Unity新版本API提示.mp4:这是一个视频教程,介绍了Unity新版本的API使用方法,对开发者了解和使用Unity的新特性很有帮助。 3. 新版Unity API提示使用说明.txt:文字版的API使用指南,提供了详细的步骤和注意事项...
Lua具有动态类型、垃圾回收机制、支持过程编程和面向对象编程,以及丰富的内置数据结构,如表(可以作为数组、哈希表或关联数组使用)。此外,Lua的语法简洁明了,易于学习和使用。 Lua 5.4.6是Lua的一个稳定版本,...
通过使用 C 函数,Lua 可以被增强以应对各种不同的领域,从而创建定制化的编程语言,这些语言共享相同的语法框架。 Lua 分发包中包含了一个名为 `lua` 的示例主机程序,该程序利用 Lua 库提供了一个完整的、独立的 ...
Lua-5.1.5版本的特性包括:支持元表和元方法,实现面向对象编程;强大的表数据结构,可以作为数组、哈希表或链表使用;以及简洁的语法,易于学习和使用。此外,Lua-5.1.5对C语言的API进行了优化,方便开发者将其嵌入...
在windows下 用lua转换将gbk转为utf 8 2013 11 16 17:56 0人...使用方法: local iconv require "luaiconv" local cd iconv new "utf 8" "gbk" local nstr err cd:iconv str ...
### Lua 实现调用 WebService 的方法 #### 一、通过 gSOAP 实现 C/C++ 调用 Web Service gSOAP 是一个强大的工具包,它简化了使用 C/C++ 语言开发 Web 服务和客户端的过程。通过 gSOAP 的帮助,我们可以轻松地使用...