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的使用方式.需要说明的 ...
随机推荐
- java中常用的转义字符
Day02_SHJavaTraing_4-3-2017 Java中允许使用转义字符‘\’来将其后的字符转变为特殊字符型常量. 一.JAVA中常用的转义字符
- RxSwift 之变换操作
https://www.aliyun.com/jiaocheng/349821.html RxSwift入坑解读-你所需要知道的各种概念 http://www.open-open.com/lib/vi ...
- CSS鼠标悬停图片加边框效果,页面布局发生错位的解决办法
CSS鼠标悬停图片加边框效果,页面布局发生错位的解决办法 .recomend-list{ width:1200px; a{ @extend %fl; margin-right: 30px; width ...
- ZBrush中Local模式的旋转
刚接触ZBrush®的小伙伴可能对Local(局部)有了简单的了解,但是大多数人对它的认识还是比较模糊的,那么在本文中小编将对local命令做详细说明.此工具可以控制视图的旋转轴心点的位置,默认情况下 ...
- LeetCode Golang 6. Z 字形变换
6. Z 字形变换 将一个给定字符串根据给定的行数,以从上往下.从左到右进行 Z 字形排列. 比如输入字符串为 "LEETCODEISHIRING" 行数为 3 时,排列如下: L ...
- luogu P3391 【模板】文艺平衡树(Splay) 非旋转treap
Code: #include<bits/stdc++.h> using namespace std; void setIO(string s) { string in=s+".i ...
- UVA1584-Circular Sequence(紫书例题3.6)
Some DNA sequences exist in circular forms as in the following gure, which shows a circular sequence ...
- js滚动事件实现滚动触底加载
移动端触底加载时前端开发过程中常用功能,主要是通过三个值的大小来进行判断: 首先介绍jquery的写法,代码如下: $(window).scroll(function(){ var windowH=$ ...
- 【【henuacm2016级暑期训练】动态规划专题 E】Destroying Roads
[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 首先. 这张图是无向无权图. 因此任意两点之间的最短路可以通过N^2的bfs轻易算出来. 即得到d[N+10][N+10] 考虑s[ ...
- Spring注解+Axis2开发WebService
用Spring注解方式: 配置扫描指定包下的类 <context:component-scan base-package="包名" /> 标识类为spring管理的 ...