Lua 与C/C++ 交互系列:动态注册枚举enum到Lua Code中,在运行时在Lua Code中获取内省信息
来源:互联网 发布:抢车位怎么恢复数据 编辑:程序博客网 时间:2024/06/05 17:25
在Lua 5.1 Reference Manual 对于Lua 值和类型的介绍。Lua是一个动态语言,在Lua中变量仅仅有值而没有类型。所以在Lua中的变量不需要声明。所以的值本身包含类型。
其实Lua 包含一种运行时类型识别,通过type()函数,可以在运行时获取值的类型。
信息来自: Lua 5.1 Reference Manual Values and Types
Lua is a dynamically typed language. This means that variables do not have types; only values do. There are no type definitions in the language. All values carry their own type.
type (variables)
Returns the type of its only argument, coded as a string. The possible results of this function are "nil" (a string, not the value nil), "number", "string", "boolean", "table", "function", "thread", and "userdata".
在C语言特征本身,不提供运行时信息。C语言的拓展集,C++语言特征本身对运行时提供支持。在C++语言中通过typeid(),dynamic_case()等函数可以获取类型的内省信息。
在Java语言中,对内省信息支持强大,spring 等库就是通过内省信息来实现的强大库。在actionscript3.0中也提供了对类的内省信息。在游戏开发中,可以利用内省信息反射出类对象,包括游戏UI编辑器都是通过内省类信息来实现的。C# 是在C++,Java语言发展而来,同时也对运行时内省提供强大支持。对于这些语言的内省信息不详细赘述。
在Python脚本语言中,PyObject 类 实现机制与Lua lua_TValue 实现机制类型,都是通过类型值int 与值相绑定. 虽然,在python 和lua语言中,只存在值,不存在类型,但是通过语言提供的函数,可以在运行时获取到值的类型。
在Lua源代码中,节选出部分与运行时信息相关的代码:
在Lua源代码中提供了8中基本内置类型,随着Lua演化,Lua的基本内置类型变化不大。以后的文章中,就详细介绍Lua类型的演化历史。
/*** basic types*/#define LUA_TNONE(-1)#define LUA_TNIL0#define LUA_TBOOLEAN1#define LUA_TLIGHTUSERDATA2#define LUA_TNUMBER3#define LUA_TSTRING4#define LUA_TTABLE5#define LUA_TFUNCTION6#define LUA_TUSERDATA7#define LUA_TTHREAD8
内置类型的实现,是通过值与类型相绑定来实现的。值是如何表示的,在Lua 作者的5.0实现介绍中有详细解释。
typedef struct lua_TValue { Value value_; //用来标示Lua的值类型,在lua作者5.0实现中有详细的介绍 int tt_; //用来标示类型,-1 -8 由上面宏定义} TValue;union Value { GCObject *gc; /* collectable objects */ void *p; /* light userdata */ int b; /* booleans */ lua_CFunction f; /* light C functions */ numfield /* numbers */};在Lua Code 运行时中,可以通过type()来获取值的类型:
type (v)
Returns the type of its only argument, coded as a string.
The possible results of this function are "nil" (a string, not the value nil), "number", "string", "boolean", "table", "function", "thread", and "userdata".
注意:lightuserdata 和 full userdata的类型都是 userdata.
type(v)在lua中关键源代码如下:
static int luaB_type (lua_State *L) { luaL_checkany(L, 1); lua_pushstring(L, luaL_typename(L, 1)); return 1;}/* Macros to access values */ //获取与值绑定的类型#define ttype(o)((o)->tt)//通过数组来返回对应的字符串类型#define ttypename(x)luaT_typenames_[(x) + 1]LUAI_DDEF const char *const luaT_typenames_[LUA_TOTALTAGS] = { "no value", "nil", "boolean", udatatypename, "number", "string", "table", "function", udatatypename, "thread", "proto", "upval" /* these last two cases are used for tests only */};
本文参考了LuaAutoC 开源项目,并节选部分代码,修改而来。本文主要展示把C 语言 struct ,enum等结构注册到Lua Code中,并可以在Lua Code中获取注册类型的运行时信息。
通过lua_pushinteger(L, 0); lua_setfield(L, LUA_GLOBALSINDEX, prefix"type_index"); 来管理生成唯一的类型ID,并存储在全局变量中,默认值为0 .
把所有类型都在全局变量表中注册,在Lua Code中就可以获取相关信息,在Lua Code中就可以内省C语言的自定义类型。
本文的核心通过一个全局唯一ID 和Lua Table本身的Hash系统来实现。代码很简单。上菜。
luademo.cpp :
extern "C" {#include "lua.h"#include "lauxlib.h"#include "lualib.h"}#define prefix "prefix_"//作者orangeduck 在他的博客中认为在动态语言中内省机制是核心。同时Lua 也是通过Type_ID来标示类型的。这与作者不谋而合。//Type_ID是通过运行时动态生成,默认从零开始。可以在运行时获取对象的类型ID.//LuaAutoC 已经在orangeduck 作者的项目中成功的应用。void luaA_open(lua_State* L) { //用来在运行时动态生成类型的唯一ID,默认开始值为零. 在全局变量表设置 prefix "type_index"的值默认为1,用来标记所有类型. lua_pushinteger(L, 0); lua_setfield(L, LUA_GLOBALSINDEX, prefix"type_index"); //在全局变量表,prefix "type_ids" 对应Table结构.称作idTable .名称-Id lua_newtable(L); lua_setfield(L, LUA_GLOBALSINDEX, prefix"type_ids"); //在全局变量表,prefix "type_names"对应Table结构.称作nameTable.名称-名称 lua_newtable(L); lua_setfield(L, LUA_GLOBALSINDEX, prefix"type_names"); //在全局变量表, prefix "type_sizes"对应Table结构.称作sizeTable.名称-大小 lua_newtable(L); lua_setfield(L, LUA_GLOBALSINDEX, prefix"type_sizes"); //与上面类型,在注册表中注册enumsTable,enum_sizesTable,enums_valuesTable用来存储c语言中的枚举值 //这些作为本例中的核心系统。可以在运行时识别C语言用户自定义struct结构的内省信息。 lua_newtable(L); lua_setfield(L, LUA_GLOBALSINDEX, prefix"enums"); lua_newtable(L); lua_setfield(L, LUA_GLOBALSINDEX, prefix"enums_sizes"); lua_newtable(L); lua_setfield(L, LUA_GLOBALSINDEX, prefix"enums_values"); } //用来演示本例子的枚举 enum Week{Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday,};typedef lua_Integer luaA_Type;// 在全局变量表中管理所有注册的类型,可以在运行时通过名字获取内省信息//在全局环境中type_idsTable 和type_namesTable 以及type_values注册类型。//如果全局环境表中已经存在该类型则直接返回类型ID,否则注册新类型///////////////////////////////////////////////////////////////////// 以Week枚举举例:// _G[prefix_type_ids]["Week"]=WeekId// _G[prefix_type_names][WeekId]=WeekName// _G[prefix_type_sizes][WeekId]=WeekSize//////////////////////////////////////////////////////////////////luaA_Type luaA_type_add(lua_State* L, const char* type, size_t size) { //获取在全局环境表中idTable,类型名称=ID lua_getfield(L, LUA_GLOBALSINDEX, prefix"type_ids"); //在idTable中获取type_name是否存在 lua_getfield(L, -1, type); //判断是否存在 if (lua_isnumber(L, -1)) { //如果已经存在,则返回类型ID luaA_Type id = lua_tointeger(L, -1); lua_pop(L, 2); return id; } else { //弹出idTable 和类型关联的ID lua_pop(L, 2); //获取自动生成的唯一索引,在运行时自动生成. lua_getfield(L, LUA_GLOBALSINDEX, prefix"type_index"); //转换成整型 luaA_Type id = lua_tointeger(L, -1);//清空栈顶 lua_pop(L, 1);//自动生成下一个唯一索引 id++;//压入到虚拟栈 lua_pushinteger(L, id);//把生成的唯一索引设置成ID,并出栈 lua_setfield(L, LUA_GLOBALSINDEX, prefix"type_index"); //获取idTable lua_getfield(L, LUA_GLOBALSINDEX, prefix"type_ids");//把自动生成的唯一ID压入栈中 lua_pushinteger(L, id);// 索引[键]=栈顶 设置idTable[type]=id lua_setfield(L, -2, type); lua_pop(L, 1); //获取类型nameTable lua_getfield(L, LUA_GLOBALSINDEX, prefix"type_names");//把唯一ID入栈 lua_pushinteger(L, id);//把类型name压入栈 lua_pushstring(L, type);//设置 索引[below 栈顶]=栈顶 nameTable[id]=type lua_settable(L, -3); lua_pop(L, 1); lua_getfield(L, LUA_GLOBALSINDEX, prefix"type_sizes"); lua_pushinteger(L, id); lua_pushinteger(L, size); lua_settable(L, -3); lua_pop(L, 1); return id; }}//注册enum类型,用来存储enum每一个枚举值// 以Week枚举举例:// _G[prefix_enums]["WeekId"]=WeekEnumTable// _G[prefix_enums_values]["WeekId"]=WeekEnumValueTable// _G[prefix_enums_sizes]["WeekId"]=WeekEnumSizeTablevoid luaA_enum_type(lua_State *L, luaA_Type type, size_t size){ lua_getfield(L, LUA_GLOBALSINDEX, prefix"enums"); lua_pushinteger(L, type); lua_newtable(L); lua_settable(L, -3); lua_pop(L, 1); lua_getfield(L, LUA_GLOBALSINDEX, prefix"enums_values"); lua_pushinteger(L, type); lua_newtable(L); lua_settable(L, -3); lua_pop(L, 1); //enum_sizesTable[name] lua_getfield(L, LUA_GLOBALSINDEX, prefix"enums_sizes"); lua_pushinteger(L, type); lua_pushinteger(L, size); lua_settable(L, -3); lua_pop(L, 1);}//实际注册enum枚举中每一个值到注册表中//注册enum类型,用来存储enum每一个枚举值// 以Week枚举举例:// _G[prefix_enums]["WeekId"]=WeekEnumTable// _G[prefix_enums_values]["WeekId"]=WeekEnumValueTable// _G[prefix_enums_sizes]["WeekId"]=WeekEnumSizeTable////// _G[prefix_enums_sizes]["WeekId"]["Monday"]=Monday//void luaA_enum_value_type(lua_State *L, luaA_Type type, int lvalue, const char* name) { //获取 _G[prefix_enums]["WeekId"]=WeekEnumTable lua_getfield(L, LUA_GLOBALSINDEX, prefix"enums"); lua_pushinteger(L, type); lua_gettable(L, -2); if (!lua_isnil(L, -1)) { //存储enum大小 lua_getfield(L, LUA_GLOBALSINDEX, prefix"enums_sizes"); lua_pushinteger(L, type); lua_gettable(L, -2); size_t size = lua_tointeger(L, -1); lua_pop(L, 2); lua_pushstring(L, name); lua_pushinteger(L, lvalue); lua_settable(L,-3); lua_getfield(L, LUA_GLOBALSINDEX, prefix"enums_values"); lua_pushinteger(L, type); lua_gettable(L, -2);size_t v =0;if (!lua_isnil(L, -1)) { v =lua_tonumber(L,-1);} lua_pushinteger(L, v); lua_getfield(L, -4, name); lua_settable(L, -3); lua_pop(L, 4); return; } lua_pop(L, 2); lua_pushfstring(L, "luaA_enum_value: Enum '%s' not registered!", luaA_typename(L, type)); lua_error(L);}//实际注册enum枚举中每一个值到注册表中//注册enum类型,用来存储enum每一个枚举值// 以Week枚举举例:// _G[prefix_enums]["WeekId"]=WeekEnumTable// _G[prefix_enums_values]["WeekId"]=WeekEnumValueTable// _G[prefix_enums_sizes]["WeekId"]=WeekEnumSizeTable////// _G[prefix_enums_sizes]["WeekId"]["Monday"]=Monday//void luaA_enum_value_type(lua_State *L, luaA_Type type, int lvalue, const char* name) { //获取 _G[prefix_enums]["WeekId"]=WeekEnumTable lua_getfield(L, LUA_GLOBALSINDEX, prefix"enums"); lua_pushinteger(L, type); lua_gettable(L, -2); if (!lua_isnil(L, -1)) { //存储enum大小 lua_getfield(L, LUA_GLOBALSINDEX, prefix"enums_sizes"); lua_pushinteger(L, type); lua_gettable(L, -2); size_t size = lua_tointeger(L, -1); lua_pop(L, 2); lua_pushstring(L, name); lua_pushinteger(L, lvalue); lua_settable(L,-3); lua_getfield(L, LUA_GLOBALSINDEX, prefix"enums_values"); lua_pushinteger(L, type); lua_gettable(L, -2);size_t v =0;if (!lua_isnil(L, -1)) { v =lua_tonumber(L,-1);} lua_pushinteger(L, v); lua_getfield(L, -4, name); lua_settable(L, -3); lua_pop(L, 4); return; } lua_pop(L, 2); lua_pushfstring(L, "luaA_enum_value: Enum '%s' not registered!", luaA_typename(L, type)); lua_error(L);}//利用C语言宏,把c语言中的enum struct 等类型作为字符串#define luaA_type(L, type) luaA_type_add(L, #type, sizeof(type))//定义enum类型#define luaA_enum(L, type) luaA_enum_type(L, luaA_type(L, type), sizeof(type))//注册枚举值#define luaA_enum_value(L,enumType,enumValue) luaA_enum_value_type(L, luaA_type(L,enumType),enumValue,#enumValue) int main(int argc, char **argv){ lua_State *L = lua_open(); /* create state */ luaL_openlibs (L); luaA_open(L); //注册枚举类型 luaA_enum(L,Week); //实际注册enum类型中的每一枚举值 luaA_enum_value(L,Week,Monday); luaA_enum_value(L,Week,Tuesday); luaA_enum_value(L,Week,Wednesday); luaA_enum_value(L,Week,Thursday); luaA_enum_value(L,Week,Friday); luaA_enum_value(L,Week,Saturday); luaA_enum_value(L,Week,Sunday); luaL_dofile (L, "demo.lua"); lua_close(L); return 1;}luademo.lua文件代码:
print("=========")--根据注册的enum名称来获取类型Idlocal WeekId =_G["prefix_type_ids"]["Week"]--获取运行时信息local nameTable =_G["prefix_type_names"][WeekId]local sizeTable =_G["prefix_type_sizes"][WeekId]print(WeekId)print(nameTable)print(sizeTable)local Week= _G["prefix_enums"][WeekId]local WeekValue= _G["prefix_enums_values"][WeekId]local WeekSize = _G["prefix_enums_sizes"][WeekId]print(Week)print(WeekValue)print(WeekSize)--获取注册的枚举值print(Week.Monday)print(Week.Tuesday)print(Week.Wednesday)print(Week.Thursday)print(Week.Friday)print(Week.Saturday)print(Week.Sunday)
运行结果如下:
本文这样就结束了。抛装引玉,如果不对的地方,请支持来,大家共享知识。
- Lua 与C/C++ 交互系列:动态注册枚举enum到Lua Code中,在运行时在Lua Code中获取内省信息
- Lua 与C/C++ 交互系列:注册枚举enum到Lua Code中
- Lua 与C/C++ 交互系列:注册枚举enum到Lua Code中
- Lua 与C/C++ 交互系列:利用模板技术在Lua Code中注册C++类
- 在LUA与C交互中遇到的问题
- Lua 在Lua中调用C函数
- 在cocos code ide中运行lua-tests例子程序
- 【Lua】Lua与C交互
- Ubuntu下安装Lua以及在C中调用Lua
- Lua 在C程序中进行Lua表操作
- Lua 在C程序中调用Lua函数
- Lua 与C交互
- Lua 与 C 交互
- Lua 与C交互
- Lua 与C交互
- Lua 与C交互
- Lua 与 C 交互
- lua与c交互
- PAT 1012 The Best Rank (25)
- C++第4章 实验
- CSS3绘制砖墙-没有用任何图片
- 设计模式之策略模式
- 《Spring技术内幕》笔记-Spring的设计理念和整体架构
- Lua 与C/C++ 交互系列:动态注册枚举enum到Lua Code中,在运行时在Lua Code中获取内省信息
- 创始人面对投资人做Pitch十二禁
- Minigui-3.0.12 开发记录
- 第一行代码 读书笔记 第2章
- UFLDL练习一(稀疏自编码器 )
- C# GetHashCode in the IEqualityComparer<T> in .NET
- 如何设置MediaWiki用户权限
- ARM上char类型问题
- 数据库 UPDATE多条记录不同值,同时UPDATE多个字段