Lua学习笔记五

来源:互联网 发布:腾讯广告大数据 编辑:程序博客网 时间:2024/05/16 18:46

Lua学习笔记五

通过前面4次的学习,我们已经具备了一些基本知识:
1、使用Lua脚本语法
2、编写Lua函数和C函数,并使他们交互
3、表和其他类型的参数的应用
4、处理函数的返回值的方法
很好,很强大。这些知识足以开启Lua世界的大门,现在让我们来真正的进入Lua的世界。

本节的目的:写一套操作动态浮点数组的函数,并把他们封装成库,侧重点为编写函数库的基本套路。 


读到这里可以发现,该系列文章是从开发者的角度来进行Lua学习,而不是一般文章中介绍Lua语法和如何编写Lua脚本的角度。事实上我也正有此意--把以前的工作全部封装成Lua接口,然后只要懂得Lua脚本语法的人,就可以参与到我们的项目里来。

 


 

记得上节我们写的2个Lua脚本函数吗?他们是:

NewWindow = CreateWindow{ x = 0,y = 0, w = 1024, h = 768} ;
AddButton{hWindow = NewWindow , x =100, y = 100, w = 75, h = 25};

但是他们还不够好,以下的方式更符合我们习惯:

NewWindow = Object.CreateWindow();
Object.AddCompent{ Type = Button, HWND = NewWindow, x = 100, y = 100, w = 75, h = 25};
Object.Show(NewWindow);
Object.Destory(NewWindow);

这个Object 就是我们封装了一套处理窗体操作的函数库。
当然,我不能给出Object库的代码,因为它太大了。不过,让我们来写一套操作动态浮点数组的函数,并把他们封装成库吧。


 RTFS,RTFS,RTRTRTFS~~

-------以下是Lua脚本--------
--test.lua
function f( x, y)
 return x + y
end

LuaC_MessageBox( "Hello World!");

--这三句是普通的函数交互,因为不能在你们的代码中通过,所以注释起来。
--NewWindow = CreateWindow{ x = 0, y = 0, w = 1024, h = 768} ;
--AddButton{hWindow = NewWindow , x =100, y = 100, w = 75, h = 25};
--ShowWindow( NewWindow);

--这是我下个要实现的目标,暂时没找到方法。
--NewWindow.add_button{ x = 100, y = 100, w = 40, h = 18, dp2 = "button1"}
--NewWindow.add_bitmap{ x = 0, y = 0, w = 640, h 480}

--这两句是基于函数库的语法。
NewObject = object.new( 8);
LuaC_MessageBox( object.count(NewObject)); 

//------------以下是test.cpp文件----------------
// 由于总是在上一次的基础上进行的添加,因此已经实现过了的函数体我就省略了。
// 这也是与“给出完整可编译代码段”的原则的妥协---不然代码就太多了。
// 这次的代码可以编译通过,我移除了Allegro相关的东西。因为Userdata的尝试是在那个环境下
// 测试的,所以才用它举例。为了保持通用性和“给出完整可编译代码段”的原则,我会尽量用
// 原生态的例子来阐述问题。

//================================================================================================================
//           Lua Test Object
//           C++ Source lua_test.cpp
//================================================================================================================
//================================================================================================================
//           Include Files
//================================================================================================================
extern "C"
{
 #include "D://My Documents//Visual Studio 2005//Projects//lua//lua//lua.h"
 #include "D://My Documents//Visual Studio 2005//Projects//lua//lua//lualib.h"
 #include "D://My Documents//Visual Studio 2005//Projects//lua//lua//lauxlib.h"
}

#include <windows.h>
#include <stdio.h>
#include <string>
using namespace std;
//================================================================================================================
//           Libraries
//================================================================================================================
#pragma comment( lib ,"D://My Documents//Visual Studio 2005//Projects//lua//release//lua.lib")
//================================================================================================================
//           Type Define
//================================================================================================================
typedef struct MyStruct_TAG
{
 int   count;
 double _array[1];
}MyStruct,*MyStruct_PTR;

//================================================================================================================
//           Global Variables
//================================================================================================================
lua_State *L;
//================================================================================================================
//           Lua Functions
//================================================================================================================
double f( double x, double y )
{
  // 已经实现
}
//================================================================================================================
//           C/C++ Functions
//================================================================================================================
int LuaC_MessageBox( lua_State *L)
{
   // 已经实现
}

int LuaC_GetObject( lua_State* L)
{
 // LuaC_GetObject( object, index)
 // 获取第1个参数
 MyStruct_PTR object = (MyStruct_PTR)lua_touserdata(L, 1);
 // 获取第2个参数
 int index = luaL_checkint( L, 2);
 // 参数有效性判断
 luaL_argcheck(L, object != NULL, 1, "`object expected");
 luaL_argcheck(L, 1 <= index && index <= object->count, 2, "index out of range");
 // 返回值压栈
 lua_pushnumber(L, object->_array[index - 1]);
 // 设置返回参数个数
 return 1;
}

 

int LuaC_CreateObject( lua_State *)
{
 int   count;
 size_t size;
 void*  lp;

 // LuaC_CreateObject(1000)
 // 获取参数
 count = luaL_checkint(L, 1);
 // 计算大小
 size = sizeof(MyStruct) + (count - 1) * sizeof( double);
 // 申请空间
 lp = lua_newuserdata( L, size);
 // 初始化
 memset( lp, '/0',size);
 // 设置个数
 ((MyStruct_PTR)lp)->count = count;

 // 设置返回值个数
 return 1;
}

int LuaC_SetObject(lua_State *L)
{
 // LuaC_SetObject( object, value, index)
 // 获取第1个参数
 MyStruct_PTR object = (MyStruct_PTR)lua_touserdata(L, 1);
 // 获取第2个参数
 double value = luaL_checknumber( L, 2);
 // 获取第3个参数
 int index = luaL_checkint( L, 3);
 // 参数有效性判断
 luaL_argcheck(L, object != NULL, 1, "`object expected");
 luaL_argcheck(L, 1 <= index && index <= object->count, 2, "index out of range");
 // 执行逻辑
 object->_array[index - 1] = value;

 // 设置返回参数个数
 return 0;
}

 

int LuaC_GetCount( lua_State* L)
{
 // LuaC_GetCount( object)
 // 获取第1个参数
 MyStruct_PTR object = (MyStruct_PTR)lua_touserdata(L, 1);
 // 参数有效性判断
 luaL_argcheck(L, object != NULL, 1, "`object expected");
 // 返回值压栈
 lua_pushnumber(L, object->count);
 // 设置返回参数个数
 return 1;
}

// 初始化库
static const struct luaL_reg object_lib[] =
{
 {"new",   LuaC_CreateObject},
 {"set",   LuaC_SetObject},
 {"get",   LuaC_GetObject},
 {"count",  LuaC_GetCount},
 {NULL, NULL}
};

int _luaopen_object (lua_State *L)
{
 luaL_openlib(L, "object", object_lib, 0);
 return 1;
}
//================================================================================================================
//           Main Functions
//================================================================================================================
int main( void)
{

 int error;

 L = lua_open();
 luaopen_base(L);
 luaL_openlibs(L);
 // 自己的扩展库
 _luaopen_object(L);

 // 注册C/C++函数
 lua_register( L, "LuaC_MessageBox", LuaC_MessageBox); 

 //luaopen_table(L);
 //luaopen_io(L);
 //luaopen_string(L);
 //luaopen_math(L);

 /*
 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);
  }
 }
 */
 // load the script
 if ( (error = luaL_dofile(L, "test.lua")) != 0)
 {
  allegro_message( "error!!");
  return 0;
 }
 /*
 double ret = f( 10, 3.4);
 printf( "ret = %f", ret);

 getchar();
 */
 lua_close( L);
 return 1;
}
END_OF_MAIN();

 


 

代码里面的注释越来越多了,不是吗?很多时候就是这个样子样,看代码比看文字要来的直接。

新出现了很多Lua库函数调用,不过都是涉及参数有效性检测的函数。所以如果你不了解用法的话,最好查找《Lua参考手册》。另外,记得下载的Lua源码吗?在名为“doc”的文件夹里有一个contents.html,打开看看吧。

好了,现在让我们把注意力转回今天的重点。

写一个自己的库的步骤是:

1、写一套功能函数,如:
int LuaC_CreateObject( lua_State *)
int LuaC_SetObject(lua_State *L)
int LuaC_GetObject(lua_State *L)
int LuaC_GetObjectCount(lua_State *L)

在这个步骤里,与编写普通的C/Lua交互函数没有什么区别。

2、声明一个Lua表,作为函数库,如:
// 初始化库
static const struct luaL_reg object_lib[] =
{
 {"new",   LuaC_CreateObject},
 {"set",   LuaC_SetObject},
 {"get",   LuaC_GetObject},
 {"count",  LuaC_GetCount},
 {NULL, NULL}
};

注意上面的粗体,声明一个作为库的表,需要使用关键字 Static const
另外这个结构体 struct luaL_reg:
typedef struct luaL_Reg {
  const char *name;
  lua_CFunction func;
} luaL_Reg;
作为库的表实际上就是一个luaL_Reg类型的数组。Lua中其他一些标准库也都是按照这个规矩来定义的。
最后这个数组需要使用一个哑员(空值)来作为结束符。

3、调用luaL_openlib();函数,如:

int _luaopen_object (lua_State *L)
{
 luaL_openlib(L, "object", object_lib, 0);
 return 1;
}

在这里,我把这个函数封装了一下,只是为了风格统一。另外,在所有我自己写的类似Lua原有函数的函数前面我都加了下划线,为了几个月后让我明白:这是我自己写的,而不是Lua自己带的。另外,这是跟Andre LaMothe学的。

4、在main函数里加载库。如:

 // 自己的扩展库
 _luaopen_object(L);

 

OK.以上就是编写自己的库的基本套路。
如果一切正常的话,会弹出一个对话框,告诉你刚刚申请的数组对象有8个元素。

好了,下一个笔记可能会是  “面向对象”、“Weaktable(弱表)”、“lightuserdata的应用”、“Metatable(元表)”、4个内容中的一个或几个。如果你学习的够快的话,代替我来写这些内容吧``