标签:
UserData(用户自定义类型)
意义:使用C语言编写的用于扩展Lua的新类型,方便使用脚本编写或者提高效率
例子:
Lua
require "array" a = array.new(1000) print(a); print(array.size(a)) for i=1,1000 do array.set(a,i,i%5 == 0) end print(array.get(a,10))
C++
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <limits.h> extern "C" { #include "lua.h" #include "lauxlib.h" #include "lualib.h" } #define BITS_PER_WORD (CHAR_BIT*sizeof(unsigned int)) #define I_WORD(i) ((unsigned int)(i) / BITS_PER_WORD) #define I_BIT(i) (1<<((unsigned int)(i) % BITS_PER_WORD)) #define checkarray(L) (NumArray*)luaL_checkudata(L,1,"LuaBook.array") //优化 typedef struct NumArray { int size; unsigned int value[1]; }NumArray; //创建数组 static int newarray(lua_State *L){ int i,n; size_t nbytes; NumArray *a; n = luaL_checkint(L,1); //检查数组个数的参数是否正确 luaL_argcheck(L,n>=1,1,"invalid size"); nbytes = sizeof(NumArray) + I_WORD(n-1)*sizeof(unsigned int); a = (NumArray*)lua_newuserdata(L,nbytes); a->size = n; for(i=0;i<=I_WORD(n-1);i++){ a->value[i] = 0; } //为所有新建的数组设置这个元表(优化) luaL_getmetatable(L,"LuaBook.array"); lua_setmetatable(L,-2); return 1; //新的userdata已在栈上 } //设置元素 static int setarray(lua_State *L){ NumArray *a = (NumArray*)checkarray(L); //优化 int index = luaL_checkint(L,2) - 1; luaL_checkany(L,3); luaL_argcheck(L,a!=NULL,1,"'array' expected"); luaL_argcheck(L,0<=index && index <a->size,2,"index out of range"); if(lua_toboolean(L,3)) a->value[I_WORD(index)] |= I_BIT(index); //设置bit else a->value[I_WORD(index)] &= I_BIT(index); //重置bit return 0; } //获取元素 static int getarray(lua_State *L){ NumArray *a = (NumArray*)lua_touserdata(L,1); int index = luaL_checkint(L,2)-1; luaL_argcheck(L,a!=NULL,1,"array expected"); luaL_argcheck(L,0<=index&&index<a->size,2,"index out of range"); lua_pushboolean(L,a->value[I_WORD(index)]&I_BIT(index)); return 1; } //获取长度 static int getsize(lua_State *L){ NumArray *a = (NumArray*)lua_touserdata(L,1); luaL_argcheck(L,a!=NULL,1,"array expected"); lua_pushinteger(L,a->size); return 1; } //模块 static const struct luaL_Reg arraylib[] = { {"new",newarray}, {"set",setarray}, {"get",getarray}, {"size",getsize}, {NULL,NULL} }; //加载 int luaopen_array(lua_State *L){ luaL_newmetatable(L,"LuaBook.array"); //(优化) luaL_register(L,"array",arraylib); return 1; } //错误处理 void err(lua_State* L,const char* fmt,...){ va_list argp; va_start(argp,fmt); vfprintf(stderr,fmt,argp); va_end(argp); lua_close(L); //exit(EXIT_FAILURE); } int main(){ lua_State* L = luaL_newstate(); luaL_openlibs(L); luaopen_array(L); if(luaL_loadfile(L,"boolArray.lua") || lua_pcall(L,0,0,0)) err(L,"cannot run config.lua:%s",lua_tostring(L,-1)); getchar(); return 0; }
原因:使用原来的方法,如果set的时候传入的是一个FILE*,由于判断是合法的,但实际上会修改到其他的内存,由于程序库不应该破坏C数据或在Lua中导致核心转储,所以需要进一步优化。
方法:辨别不同类型的userdata的方法是为每种类型创建一个唯一的元表
上面已经实现了userdata的定义,在lua中可以调用到指定的方法,但是不符合面向对象的访问习惯,这里做一下优化
当我们访问size()的时候不需要使用array.size(a)的方式,而是直接使用a:size()
版权声明:本文为博主原创文章,未经博主允许不得转载。
标签:
原文地址:http://blog.csdn.net/zh13544539220/article/details/47417491