`
javababy1
  • 浏览: 1166379 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

Lua学习笔记五--真正的入门:编写Lua扩展库

阅读更多

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
//================================================================================================================
#pragmacomment( lib ,"D:\\My Documents\\Visual Studio 2005\\Projects\\lua\\release\\lua.lib")
//================================================================================================================
//Type Define
//================================================================================================================
typedef struct MyStruct_TAG
{
intcount;
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 *)
{
intcount;
size_tsize;
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个内容中的一个或几个。如果你学习的够快的话,代替我来写这些内容吧``

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics