lua-C++ userdata使用
lua-C++ userdata使用
所负责的产品使用非常灵活,可设置的参数上千个,而且还支持用户用lua进行流程控制,所以开发中要用到很多lua、C++混合编程。之前对这些也还是一知半解,只会依葫芦画瓢修改一些bug或者加些小小的新功能,而没有对这方面的知识进行系统性的学习和总结,蹭中秋假期,补充点这方面的知识。
问题定义
在开发过程中,我们经常会有这样的需求,可以分为一下几部完成:
- 在lua中通过自定义C-API得到一个在C/C++中定义好的对象(数据结构);
- lua通过C-API对该对象进行一系列操作。
所以这里涉及到两个核心问题,一是如何把一个C/C++的对象传给lua;二是lua怎样把该对象传回C/C++,而且要提供一种C/C++能够确认该对象数据类型的机制。
下面我们举一个例子,在C/C++中定义一个矩形(rectangle)的数据结构,提供C-API,能够使用lua读出这个矩形的信息。
#ifdef __cplusplus
extern "C" {
#endif
#include<lua.h>
#include<lualib.h>
#include<lauxlib.h>
#ifdef __cplusplus
}
#endif
typedef struct dt_rectangle_s
{
double left;
double bottom;
double right;
double top;
} dt_rectangle_t;
typedef struct dt_line_s
{
double start;
double end;
} dt_line_t;
/**
调用lua_newuserdata新建一个rectangle对象
*/
static int new_rectangle(lua_State *L)
{
dt_rectangle_t *p = (dt_rectangle_t*)
lua_newuserdata(L, sizeof(dt_rectangle_t));
p->left = 1;
p->right = 2;
p->bottom = 3;
p->top = 4;
return 1;
}
static int get_rect_left(lua_State *L)
{
dt_rectangle_t *p = (dt_rectangle_t*)
lua_touserdata(L, -1);
lua_pushnumber(L, p->left);
return 1;
}
/**
调用lua_newuserdata新建一个line对象
*/
static int new_line(lua_State *L)
{
dt_line_t *p = (dt_line_t*)
lua_newuserdata(L, sizeof(dt_line_t));
p->start = 100;
p->end = 200;
return 1;
}
static luaL_Reg myfuncs[] = {
{"new_rectangle", new_rectangle},
{"get_rect_left", get_rect_left},
{"new_line", new_line},
{NULL, NULL}
};
extern "C" int luaopen_userdatatest(lua_State *L)
{
luaL_register(L, "userdatatest", myfuncs);
return 1;
}
编译之后运行:
$ lua
Lua 5.1.5 Copyright (C) 1994-2012 Lua.org, PUC-Rio
> require("userdatatest")
> rect = userdatatest.new_rectangle()
> print(userdatatest.get_rect_left(rect))
1
看似可以工作了,但却存在一个问题,如:
> line = userdatatest.new_line()
> print(userdatatest.get_rect_left(line))
100
将一个line对象传给了get_rect_left函数,其返回了line的start,这种行为可以理解(在C++中只是得到了一个指针,我们返回的是指针指向第一个double类型),但是这回存在很多问题,比如访问越界之类的。
利用metatable标记自定义数据
metatable是lua中一个非常重要的概念,在lua程序中只能对table设置元表,而不能对其他的类型设置,但是在C/C++中却可以用lua_setmetatable对userdata设置元表,我们这是利用了这一点来标记userdata。
前面的示例程序在new_rectangle、get_rect_left和luaopen_userdatatest函数稍作改变即可:
static int new_rectangle(lua_State *L)
{
dt_rectangle_t *p = (dt_rectangle_t*)
lua_newuserdata(L, sizeof(dt_rectangle_t));
p->left = 1;
p->right = 2;
p->bottom = 3;
p->top = 4;
// 绑定元表
luaL_getmetatable(L, "rectangle");
lua_setmetatable(L, -2);
return 1;
}
static int get_rect_left(lua_State *L)
{
//检查(L, -1)元表是否为rectangle
void *p = luaL_checkudata(L, -1, "rectangle");
if(!p) {
luaL_error(L, "p is NULL\n");
}
lua_pushnumber(L, ((dt_rectangle_t*)p)->left);
return 1;
}
extern "C" int luaopen_userdatatest(lua_State *L)
{
// 新建一个元表,挂到LUA_REGISTRYINDEX
luaL_newmetatable(L, "rectangle");
luaL_register(L, "userdatatest", myfuncs);
return 1;
}
运行结果:
$ lua
Lua 5.1.5 Copyright (C) 1994-2012 Lua.org, PUC-Rio
> require("userdatatest")
> rect = userdatatest.new_rectangle()
> print(userdatatest.get_rect_left(rect))
1
> line = userdatatest.new_line()
> print(userdatatest.get_rect_left(line))
stdin:1: bad argument #-1 to 'get_rect_left' (rectangle expected, got userdata)
stack traceback:
[C]: in function 'get_rect_left'
stdin:1: in main chunk
[C]: ?
最近开发中遇到一个需求,要提供一个C-API判断lua对象是否属于某一指定的类型,如果是返回true,否则返回false。前面的例子中,luaL_checkudata判断不是该类型就报错返回,跟该需求有点不符,我们可以将luaL_checkudata源码稍作更改即可:
static void *luaL_checkmydata (lua_State *L, int ud, const char *tname) {
void *p = lua_touserdata(L, ud);
if (p != NULL) { /* value is a userdata? */
if (lua_getmetatable(L, ud)) { /* does it have a metatable? */
lua_getfield(L, LUA_REGISTRYINDEX, tname); /* get correct metatable */
if (lua_rawequal(L, -1, -2)) { /* does it have the correct mt? */
lua_pop(L, 2); /* remove both metatables */
return p;
}
}
}
//注释掉这个报错返回
//luaL_typerror(L, ud, tname); /* else error */
return NULL; /* to avoid warnings */
}
$ lua
Lua 5.1.5 Copyright (C) 1994-2012 Lua.org, PUC-Rio
> require("userdatatest")
> line = userdatatest.new_line()
> userdatatest.get_rect_left(line)
stdin:1: p is NULL
stack traceback:
[C]: in function 'get_rect_left'
stdin:1: in main chunk
[C]: ?
> rect = userdatatest.new_rectangle()
> print(userdatatest.get_rect_left(rect))
1
--http://www.jellythink.com/archives/587 Lua中的userdata
--http://ju.outofmemory.cn/entry/103 lua metatable使用和源码分析(三)
lua-C++ userdata使用的更多相关文章
- Lua 之 userdata
Lua 之 userdata 在Lua中可以通过自定义类型(user data)与C语言代码更高效.更灵活的交互,从而扩展Lua能够表达的类型. full userdata full userdata ...
- Lua继承userdata
http://blog.csdn.net/mywcyfl/article/details/37765751 http://blog.csdn.net/teng_ontheway/article/det ...
- Lua中的userdata
[话从这里说起] 在我发表<Lua中的类型与值>这篇文章时,就有读者给我留言了,说:你应该好好总结一下Lua中的function和userdata类型.现在是时候总结了.对于functio ...
- Lua.LearningLua.7-userdata
Learning Lua: 7 - userdata 1. Userdata basic "There are eight basic types in Lua: nil, boolean, ...
- lua: Learning Official Doc notes
dynamically typed vars: basic types: nil, boolean, number, string, function, userdata, thread & ...
- [lua] mac上如何编译snapshot(检测Lua中的内存泄露)
最近我们的unity手游频繁闪退,只要进入战斗场景,之后一段时间就会闪退,如果是在unity编辑器中则会报出not enough memory的错误!猜测应该是有内存泄漏: 由于我们使用了tolua, ...
- 用好lua+unity,让性能飞起来——lua与c#交互篇
前言 在看了uwa之前发布的<Unity项目常见Lua解决方案性能比较>,决定动手写一篇关于lua+unity方案的性能优化文. 整合lua是目前最强大的unity热更新方案,毕竟这是唯一 ...
- Lua基础语法讲解
Lua 是什么? Lua 是一种轻量小巧的脚本语言,用标准C语言编写并以源代码形式开放, 其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能. Lua 是巴西里约热内卢天主教大学( ...
- 浅析C++绑定到Lua的方法
注:原文也在公司内部论坛上发了 概述 尽管将C++对象绑定到Lua已经有tolua++(Cocos2d-x 3.0用的就是这个).LuaBridge(我们游戏client对这个库进行了改 ...
- Step By Step(userdata)
Step By Step(userdata) 在Lua中可以通过自定义类型的方式与C语言代码更高效.更灵活的交互.这里我们通过一个简单完整的示例来学习一下Lua中userdata的使用方式.需要说明的 ...
随机推荐
- redux原理
Redux实现原理 不同组件需要依赖同一个数据的时候,就需要状态提升至这些组件的根组件. redux是状态统一管理工具,需要使用它的原因是: 组件之间通信统一管理,方便代码维护. React中有一个特 ...
- css3子级高度与父级同高,内容垂直居中
.E-wrap{ overflow: hidden; position: relative; border: 1px solid #ccc; margin: 30px auto 0; width: 5 ...
- UWP 读取XML文件
一.读取本地XML文件时要将xxx.xml文件的“生成操作”改为“嵌入的资源”会比较好,在手机上运行的话需要改为“内容” <?xml version="1.0" encodi ...
- 基于mysql主从同步的proxy读写分离
mysql-proxy 简介 MySQL Proxy是一个处于你的client端和MySQL server端之间的简单程序,它可以监测.分析或改变它们的通信.它使用灵活,没有限制,常见的用途包括:负载 ...
- mac下生成ssh key
ssh -v usage: ssh [-1246AaCfGgKkMNnqsTtVvXxYy] [-b bind_address] [-c cipher_spec] [-D [bind_address: ...
- 脚本_求和100以内的正整数.sh
#!bin/bash#功能:求和100以内的正整数#作者:liusingbon#seq 100 可以快速自动生成 100 个整数sum=0for i in $(seq 100)do sum=$[ ...
- CF1012B Chemical table 构造_思维_并查集
我们可以将横坐标和纵坐标看成是点.发现这些点之间是有传递性的. 题中说明,如果有矩阵中三个顶点被选,则底角的点也会被覆盖,发现这些点之间是有传递性的.那么我们最终达到的目的就是使整个图中只有 111 ...
- Pyhton学习——Day10
#################################################################################################### ...
- webpack——entry,output,plugins,loader,chunk知识
entry:打包入口 代码的入口,找到依赖模块 打包的入口,webpack去哪个文件找依赖,或是去那个文件依赖的依赖 可以是一个或者多个入口 例如: 1.module.exports={ entry: ...
- JavaFX 的 UI 控件集 ControlsFX
出处:http://www.oschina.net/p/controlsfx JavaFX 的 UI 控件集 ControlsFX ControlsFX 开源项目旨在为 JavaFX 开发提供更多的 ...