Lua学习笔记四
通过上一节的知识,我们学会了如何利用表来作为参数,这样我们能实现的功能更多了。但是有一点是没有涉及到的,那就是返回值,而返回值的讨论不能不提userdata类型。
本节的目的:讨论如何处理Lua返回值和Userdata类型的应用。
本章涉及一些Allegro的知识,但是这不是重点。所以当你看到不熟悉的代码段时,不必太在意,把注意力放在编写Lua函数的套路上。
现在我可以在脚本中写下“CreateWindow{x=0,y=0,w=1024,h=768} ”这样的语句来控制程序在内存中创建一个窗口了,很美妙是不是?
但是我现在要实现“AddButton{x=100,y=100,w=75,h=25}”这样添加控件,应该如何做呢?
首先我得让AddButton接受一个类似窗口句柄的参数,那样AddButton才知道往哪个窗口里添加一个新按钮。
因此CreateWindow就得返回这个窗口句柄。
OK。新的LUA语句象这个样子:
NewWindow = CreateWindow{ x = 0,y = 0, w = 1024, h = 768};
AddButton{hWindow = NewWindow , x =100, y = 100, w = 75, h = 25};
看起来真好,现在让我们来实现它。
RRRRRRRTFS!
-------以下是Lua脚本--------
--test.lua
NewWindow = CreateWindow{ x = 0, y = 0, w = 1024, h = 768};
AddButton{hWindow = NewWindow , x =100, y = 100, w = 75, h = 25};
---------绝对不会通过LuaEdit语法测试--------------
//------------以下是test.cpp文件----------------
// 由于总是在上一次的基础上进行的添加,因此已经实现过了的函数体我就省略了。
// 这也是与“给出完整可编译代码段”的原则的妥协---不然代码就太多了。
// 另外这次的代码是没办法直接通过编译的,因为使用到了Allegro库和一套自己编写的控件。
// 但是这些代码跟包含Allegro相关的代码没有区别--注意如何使用Lua的套路就好。
//================================================================================================================
//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"
}
// 这是一套控件,利用了Allegro库,不必在意。
#include "d:/My Documents/Visual Studio 2005/Projects/Demo/Demo/Components.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")
//===================================================================================================
// macro
//===================================================================================================
// 计算Dialog数组长度
#define DLG_COUNT(x)( sizeof(x)/sizeof(DIALOG))
// 计算Dialog数组的大小
#define DLG_SIZEOF(x)( sizeof( *x) + (x##->count -1) * sizeof( x##->lpdialog[0]))
// 在堆上初始化变量
#define NEW(x)( (x##_PTR)malloc( sizeof(x)))
//================================================================================================================
//Global Variables
//================================================================================================================
// 定义的结构体。因为在Allegro中,窗体是一个Dialog类型的数组。不必在意。
typedef struct DIALOG_ARRAY_TAG
{
intcount;
DIALOGlpdialog[1];
}DIALOG_ARRAY, *DIALOG_ARRAY_PTR;
//================================================================================================================
//Global Variables
//================================================================================================================
lua_State *L;
//================================================================================================================
//Lua Functions
//================================================================================================================
double f( double x, double y )
{
}
//================================================================================================================
//C/C++ Helper Functions
//================================================================================================================
// 获取t[k](表t中字段k)的值
void _lua_getfield( lua_State* L, char* key, void* ret, int type_flags)
{
}
//================================================================================================================
//C/C++ Functions
//================================================================================================================
int LuaC_MessageBox( lua_State *L)
{
}
int LuaC_MessageBoxEx( lua_State *L)
{
}
// 创建一个新DIALOG数组
// 返回该数组指针
int CreateWindow( lua_State* L)
{
// Lua Var
int x,y,w,h;
void* lp;
// NewWindow = CreateWindow{ x = __in, y = __in, w = __in, h = __in}
// 从堆栈上获取参数
_lua_getfield( L, "x", &x, GTC_INT);
_lua_getfield( L, "y", &y, GTC_INT);
_lua_getfield( L, "w", &w, GTC_INT);
_lua_getfield( L, "h", &h, GTC_INT);
// allegro var 不必在意
DIALOG_ARRAY_PTR new_dialog = NEW(DIALOG_ARRAY);
new_dialog->count = 0;
DIALOG lpbasic_dialog[] = //一个基本的Allegro窗体数组模板,不必在意
{
/* (dialog proc)(x)(y)(w)(h)(fg)(bg)(key)(flags)(d1)(d2)(dp)(dp2)(dp3) */
{ d_clear_proc,0,0,0,0,0, 0, 0, 0, 0,0,NULL,NULL,NULL},
{ d_yield_proc,0,0,0,0,0, 0, 0, 0, 0,0,NULL,NULL,NULL},
{ NULL}
};
//将窗体模板添加到新的数据结构DIALOG_ARRAY,不必在意
new_dialog = add_object(DLG_COUNT(lpbasic_dialog), new_dialog, lpbasic_dialog);
//使用获得的参数
new_dialog->lpdialog[0].x = x;
new_dialog->lpdialog[0].y = y;
new_dialog->lpdialog[0].w = w;
new_dialog->lpdialog[0].h = h;
// 返回值压栈
lp = lua_newuserdata( L, DLG_SIZEOF(new_dialog));
// 拷贝数组内容
memcpy( lp, new_dialog, DLG_SIZEOF(new_dialog));
// 返回压栈参数的个数
return 1;
}
//================================================================================================================
//Main Functions
//================================================================================================================
int main( void)
{
int error;
L = lua_open();
luaopen_base(L);
luaL_openlibs(L);
// 注册C/C++函数
lua_register( L, "LuaC_MessageBox", LuaC_MessageBox);
lua_register( L, "LuaC_MessageBoxEx", LuaC_MessageBoxEx);
lua_register( L, "CreateWindow", CreateWindow);
// load the script
// 加入了错误处理
if ( (error = luaL_dofile(L, "test.lua")) != 0)
{
MessageBox( NULL, "出错啦:执行脚本出错!","Lua Test", MB_OK);
return 0;
}
getchar();
lua_close( L);
return 1;
}
恩,这次笔记需要注意的地方是不是醒目多了?
现在让我们来逐个分析:
返回值为UserData类型。
OK,我知道我违反了介绍的原则---先易后难,但是普通的返回值确实是很简单的事情,所以在我们讨论清楚userdata类型之后,再一句话带过普通类型的返回值。
int CreateWindow( lua_State* L)
该函数中第1个有意思的地方在于结尾对返回值的压栈:
// 返回值压栈
lp = lua_newuserdata( L, DLG_SIZEOF(new_dialog));
Lua中有很多把各类返回值压栈的函数,只要你在Lua参考手册中搜索“lua_push”,你可以得到如下结果:
lua_pushboolean
lua_pushinteger
lua_pushfstring
lua_pushlstring
lua_pushnil
lua_pushnumber
.....
有很多这样的函数,解释可以参看参考手册。
我想谈的是他们的共性:这一系列的类型压栈都是已经分配了内存空间的类型。
所以你找不到函数 lua_pushuserdata,原因是Userdata实际是指一块内存空间,就象malloc出来的一样。不同的是,这段空间是在Lua用于交互的栈(luaState* L)上进行分配的。所以你要将自己的数据类型压栈的话,就需要按照以下步骤来:
1、调用lua_newuserdata()函数申请指定大小的 userdata类型,该函数返回指向新内存的指针。如:
lp = lua_newuserdata( L, DLG_SIZEOF(new_dialog));
2、改变lp指向的这段内存的内容--随便写些000111进去,或者改成你要的数据。但是有一点需要注意的是,不要尝试改变该块内存的大小,否则会对Lua的栈造成破坏。何况Lua也不会让你改变这块内存~
第2个有意思的地方是如何利用刚刚申请的这段空间。因为在Lua的栈上,所以操作起来不如在堆上的数据那么自由,把堆上的数据往这个栈拷贝的时候会出现失败的情况---至少我用memmove函数进行操作时失败了。
// 拷贝数组内容
memcpy( lp, new_dialog, DLG_SIZEOF(new_dialog));
现在再来谈谈普通的返回值压栈:调用对应类型的函数!
最后,告诉Lua,你要返回的参数个数,在这里,我要返回刚才创建的窗体树组,所以是1个。
// 返回压栈参数的个数
return 1;
分享到:
相关推荐
lua学习笔记
自己学习lua记得笔记,做任务用的~很基础的东西,想要的拿走,免费
**lua (VC环境) 学习笔记** 在深入学习lua编程语言并将其应用于Microsoft Visual C++(VC环境)时,我们需要了解几个关键知识点。lua是一种轻量级的脚本语言,设计目标是作为嵌入式语言,使得游戏开发、系统管理、...
### Lua基础学习笔记 #### 一、Lua简介与特点 Lua是一种轻量级且高效的脚本语言,广泛应用于游戏开发、网页应用、图形界面等领域。对于已有其他编程语言基础的学习者来说,掌握Lua通常较为迅速。Lua的设计哲学是...
4. ** 操作符与控制结构 **:Lua支持常见的算术和比较操作符,如+、-、*、/、==、<等。控制结构包括if...then...else、while、for循环以及do...end块。 5. ** 文件I/O **:Lua提供了简单易用的文件操作接口,可以...
【cocos2dx_lua开发笔记】是一篇个人实践总结,主要涵盖了使用cocos2dx_lua进行游戏开发的一些关键点,包括...通过学习和理解这些笔记,开发者能够更好地理解和运用cocos2dx_lua进行游戏场景、UI元素和动画效果的构建。
【Lua学习笔记之表达式】 在Lua编程语言中,表达式是构成程序的基本元素,用于表示计算或逻辑操作。表达式的结果可以是一个值,也可以是一个布尔值,这取决于执行的操作。下面我们将深入探讨Lua中的各种表达式类型...
【Lua (VC环境) 学习笔记】 Lua是一种轻量级的、开源的脚本语言,主要用于嵌入式系统和游戏开发。它以其简洁的语法、高效性和易于集成的特点受到广泛欢迎。在VC(Visual C++)环境中使用Lua,可以为C++应用程序提供...
Lua的table元表自我学习笔记分享。--lua元表总结 --1、__index的运用 (调用table的一个不存在的索引时,会使用到元表的__index元方法,搜索元表是否也有改索引,__index可以是一个函数也可是一个table。)
四、Cocos2dx-Lua 游戏开发流程 1. 创建项目:使用 Cocos Console 或者 Xcode、Android Studio 等工具创建新的 Cocos2d-x Lua 项目。 2. 编写 Lua 脚本:在项目的 scripts 目录下,编写游戏的各个模块,如主菜单、...
Lua的类型与值的学习笔记为我们提供了对这些基础知识的全面了解,对于Lua新手来说是一份宝贵的资料。通过这些知识点的学习,开发者可以更加有效地编写Lua程序,并在日常开发中避免一些常见错误。
这个"Lua使用笔记"的压缩包包含了三个文件:hello3.lua、hello.lua和hello2.lua,这些文件很可能是 Lua 的示例代码或练习脚本,通过它们我们可以学习和理解 Lua 的基本语法和特性。 首先,我们来看一下 Lua 的基础...
Lua是一种轻量级的嵌入式脚本语言,它的语法简洁且易于学习,而C++则以其强大的性能和灵活性著称。将两者结合可以让我们在C++程序中利用Lua的便利性编写脚本,进行逻辑控制或动态行为。 一、Lua与C++的交互 1. Lua ...
【标题】中的“自我学习笔记--LUA;python:网络编程等”表明这是一份包含LUA和Python语言,特别是关于网络编程的学习资料。LUA和Python都是编程语言,广泛应用于游戏开发、脚本编写、自动化任务以及网络服务等领域。 ...
### Lua基础应用知识点详解 #### 一、Lua简介与特性 ...以上内容覆盖了Lua的基本语法和常用操作,是学习Lua的入门必备知识点。对于从事Unity3D开发或者对Lua感兴趣的朋友来说,掌握这些内容将极大地提高编程效率。
selectExample(1, 2, 3, 4, 5) -- 输出参数个数: 5 和所有参数: 1 2 3 4 5 ``` 总结来看,Lua中的函数特性非常灵活且功能强大,掌握如何使用多返回值、变长参数、闭包以及select函数,对于编写有效的Lua代码至关...
本项目为《Spring实战》英文原版书籍的Java实现学习笔记与源码分析,包含186个文件,主要采用Java语言编写,辅以HTML、CSS、Lua等语言。文件类型多样,涵盖163个Java源文件、5个HTML文件、2个Git忽略文件、2个...
4. **Lua与C++的接口**:理解`lua_State`句柄,它是Lua引擎的入口点,通过它调用luaL_openlibs加载标准库,以及lua_pcall和lua_call等函数执行和管理Lua函数。 5. **错误处理与调试**:学会在VS2008中设置断点,...