您的位置:首页 > 编程语言 > Lua

Lua 与C/C++ 交互系列: Lua调用C/C++函数(4-1)

2015-06-21 07:27 579 查看
1、本文将继续讲解在Lua Code中调用注册的C函数.偶在学习本文知识点时,由于知识点的遗漏,在这个上面浪费了大量时间和精力。一直都没有没明白,Lua 通过面向对象的方式是如果调用注册的C函数。在Programming In Lua一书,有对这个方面的讲解。但是当时看书,就是不理解。因为在前面的章节中,有一个重要的知识点被遗漏。在Lua 元方法中,有两个特别重要的.__index 和__newindex被我遗漏。这两个元方法特别重要,对于定义和拓展Lua的机制,基本依靠这两个。

2、本文首先由Lua Code中对__index 和__nexindex 的讲解引入,来对通过Lua Code 面向对象调用注册的C函数。

2.1 在Lua Code中讲解metatable中__index和__newindex两个重要的元方法

2.2 注册C模块

2.3 通过Lua Code面向对象调用注册的C函数。

3、本文作为在Lua 中实现面向对象编程和在Lua中绑定C++对象的一个铺垫。在Lua的演化中,作者并没有把面向对象特点加入的Lua的语言中,但是,一个语言的发展深入当时环境的影响,Lua在发展时,由用户的原因,被迫满足在Lua中提供面向对象的需求。在Lua中实现面向对象只要依靠Table和metatable两个机制,来实现面向对象的形式。

4、本文不是详细讲解Lua 编写语言的知识点,但是会总结关键知识点。对于Lua本身的学习,主要Programming In Lua 和Lua Reference Manual 足以.

5.1 下面LuaCode将讲解元方法和Lua Code中实现面试对象调用:

object ={}
methodTab ={}

setmetatable(object, methodTab)

methodTab.__tostring=function()
    print("object tostring...")
    return "object"
end
methodTab.__call=function() 
   print("object call...")
end
methodTab["method"]=function()
   print("object method...")
   return "object method"
end
object() --对Table进行函数调用,对于__call 元函数
tostring(object)
print(object)
<span style="color:#ff0000;">methodTab.__index =methodTab  --__index元方法表示对Object Table的进行定义.当调用Object["method"]获取Object指定键操作时,如果Object中不存在指定键,</span>
<span style="color:#ff0000;">则在查询Object是否存在metatable,如果存在metatable则在metatable中查询指定键元素。</span>
local m =object["method"]

print(m)
m()
<pre name="code" class="plain">object["method"]()



由于在忽悠__index 和__nexindex知识点,在后来的学习中,总是理解不清楚,浪费了大量的时间。在此特别罗列出知识点,希望能够减少读者在错误的道路上浪费的时间。

5.2 下面例子代码来自于Programming In Lua的章节中。来讲述注册C模块和通过Lua面向对象调用注册的C函数。在Lua中面向对象调用,实际是Lua作者不想把面向对象机制引入Lua语言本身,导致语言复杂性,而引入一种语法糖来实现面向对象调用。在Lua作者的文章中多次提及Lua语言本身不提供面向对象机制,但是提供对面向对象的支持。

后面的文章会继续设计Lua的面向对象东东,包括对Lua作者面向对象观点的翻译。

extern "C" 
{
	#include <lua.h> 
	#include <lualib.h>
	#include <lauxlib.h>
}
#include <stdio.h>
#define CnExampleStr "example"
//在C语言中的结构体,绑定到Lua语言中
typedef struct 
{
  int Val;
  int Open;
} ExampleType, * ExamplePtrType;
static ExamplePtrType LclExamplePtrGet(lua_State *L,int StkPos)
{
  ExamplePtrType ExamplePtr = (ExamplePtrType)luaL_checkudata(L, StkPos, CnExampleStr);
  if (! ExamplePtr->Open)
    luaL_error(L, "attempt to use a closed " CnExampleStr);
  return ExamplePtr;
}

static int LclExampleStr(lua_State *L)
{
  ExamplePtrType  ExamplePtr = (ExamplePtrType)luaL_checkudata(L, 1, CnExampleStr);
  if (ExamplePtr->Open)
    lua_pushfstring(L, CnExampleStr " (%d)", ExamplePtr->Val);
  else lua_pushfstring(L, CnExampleStr " (%d, closed)", ExamplePtr->Val);
  return 1;
}
//获取c结构体数据
static int LclExampleGet(lua_State *L)
{ 
  ExamplePtrType ExamplePtr = LclExamplePtrGet(L, 1);
  lua_pushnumber(L, ExamplePtr->Val);
  printf("Retrieving value of " CnExampleStr " (%d)\n", ExamplePtr->Val);
  return 1;
} 
//设置c结构体数据
static int LclExampleSet(lua_State *L)
{ 

  ExamplePtrType ExamplePtr = LclExamplePtrGet(L, 1);
  int  Val = luaL_checkint(L, 2);
  printf("Setting value of " CnExampleStr " from %d to %d\n",
    ExamplePtr->Val, Val);
  lua_pushnumber(L, ExamplePtr->Val);
  ExamplePtr->Val = Val;
  return 1;
}
//关闭结构体
static int LclExampleClose(lua_State *L)
{
  ExamplePtrType ExamplePtr = LclExamplePtrGet(L, 1);
  printf("Closing " CnExampleStr " (%d) explicitly\n", ExamplePtr->Val);
  ExamplePtr->Open = 0;
  return 0;
}
//通过Lua Code构造C语言结构体
static int LclExampleOpen(lua_State *L)
{ 
  //接受LuaCode传递参数
  int Val = luaL_checkint(L, 1);
  //申请由lua GC管理下的内存
  ExamplePtrType  ExamplePtr =(ExamplePtrType)lua_newuserdata(L, sizeof(ExampleType));
  printf("Opening " CnExampleStr " (%d)\n", Val);
  //设置数据
  ExamplePtr->Val = Val;
  ExamplePtr->Open = 1;
  ////在注册表中查询注册的C函数
  luaL_getmetatable(L, CnExampleStr);
  //设置userdata的CnExampleStr的metatable
  lua_setmetatable(L, -2);
  return 1;
}
void luaopen_register(lua_State *L)
{
 static const luaL_reg regMethod[] = 
 {
	{"open", LclExampleOpen},
    {"close", LclExampleClose},
    {"get", LclExampleGet},
    {"set", LclExampleSet},
    {"tostring", LclExampleStr},
    {NULL, NULL}
  }; 
  //创建一个metatable用于标识userdata唯一性
  luaL_newmetatable(L, CnExampleStr);
  luaL_register(L,"ud_example",regMethod);
}
int main(int argc, char **argv)
{
	/* initialize Lua */
	lua_State* L = lua_open();
	luaL_openlibs(L);
	//luaopen_ud_example(L);
	luaopen_register(L);
	luaL_dofile(L, "sample_6.lua");
	/* cleanup Lua */
	lua_close(L);
	return 1;
}


sample_6.lua 测试代码如下:

print("sample_6.lua")

local ud1 =ud_example.open(1)
print(ud1)
print(ud_example.tostring(ud1))

local a =ud_example.get(ud1)
print("a:"..a)

local b =ud_example.set(ud1,2)
print("b="..b)


整个注册模块和Lua Code调用演示模块已经完成。至于Lua Code如何管理C/C++对象的生命周期,会在后面陆续介绍。在这个例子中没有涉及到Lua GC垃圾收集器。

到目前为止只要记住,Lua为了提高用户自定义数据类型,提供了userdata数据类型。userdata数据类型的生命周期由Lua GC管理。当userdata管理的C/C++对象时,当GC把userdata当做垃圾收集时,会调用__gc userdata的元方法。假如,C/C++对象生命周期由Lua GC管理,那么此时是释放C/C++对象的唯一机会。

本文中涉及到环境和userdata的如何使用?可以参考Lua Reference Manual .在本系列文章中,将会不断的讲解userdata的由来和使用方式方法。

本来本文应该完成第三部分,通过Lua Code面向对象语法糖调用注册的C函数,无奈,这内容比较多,涉及知识点较多。和老婆约好了,11点去同事家完,不想本文草草了事情,所以第三部以及涉及的知识点,将在下一张详细讲述。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: