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

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点去同事家完,不想本文草草了事情,所以第三部以及涉及的知识点,将在下一张详细讲述。

时间: 2024-10-13 13:09:36

Lua 与C/C++ 交互系列: Lua调用C/C++函数(4-1)的相关文章

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

1.本文继续讲解Lua调用C/C++函数,本文的重点是通过metatable来实现Lua Code面向对象调用注册的C函数.本文中涉及的Environment 伪索引,userdata 以及GC 垃圾回收器的内容,都是简单的讲解.不作为本文的重点,这些内容都将在以后的章节中继续讲解. 2.本文涉及的到主要知识点补充说明. 2.1 void *lua_newuserdata (lua_State *L, size_t size); 函数说明 This function allocates a ne

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

1.Lua API中提供注册C函数关键在lua_pushcclouse()函数.该函数可以在Lua Code中定义C函数. 但是Lua 提供了几个常用的宏定义,用于注册C函数. 这几个宏定义为: /#define lua_pushcfunction(L,f) lua_pushcclosure(L, (f), 0) #define lua_register(L,n,f) (lua_pushcfunction(L, (f)), lua_setglobal(L, (n))) LUALIB_API vo

Lua 与C/C++ 交互系列: Lua调用C/C++函数(2).

1.本文将使用void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n); 来讲解在Lua Code中注册C函数,其他注册方式将在下一篇文章中讲解. When a C function is created, it is possible to associate some values with it, thus creating a C closure ; these values are then accessible to

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

在学习Lua和C/C++过程中,在这个过程花费了不少时间.总是在几个地方卡住.Programming  In Lua 和Lua 5.1 Reference Manual  为主要学习资料. 但是Lua 5.1 Reference Manual 在演化过程中,把对虚拟栈管理部分分散在不同的章节里面.Lua 5.0 Reference Manual 版本却有这一个章节.然后,后来在lua 源代码中找到了对虚拟栈管理东东.还有在Lua的不同版本中,对注册C函数也有不同的演化.比如Function lu

Lua 与C/C++ 交互系列:Light userdata翻译

利用零碎的时间,先把以后用的知识点提前准备好.最近比较忙,正在准备一篇绑定C++对象到Lua中.但是,不想轻易下手,希望做足准备. 这篇翻译来自于lua-users.org   ,原文地址. Light User Data Light userdata, like heavy userdata, are a form of userdata, which is one of the basic data types in Lua .Light userdata are characterized

Lua 与C/C++ 交互系列:注册枚举enum到Lua Code中

在Lua Code中注册C/C++的枚举非常容易,就像注册全局变量一样.我们使用枚举名称作为命名空间,来避免注册的枚举发生冲突.注册的枚举存储在全局环境(线程环境)中. 当在Lua Code中访问枚举时,通过名称来访问对应的值. sample_9.cpp   c++代码如下: //在Lua Code中注册的enum,为了避免冲突,以名称作为enumTable来存储 enum Week { Monday, Tuesday, Wednesday, Thursday, Friday, Saturday

Lua 与C/C++ 交互系列:动态注册枚举enum到Lua Code中,在运行时在Lua Code中获取内省信息

在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 variable

Lua 与C/C++ 交互系列:注冊枚举enum到Lua Code中

在Lua Code中注冊C/C++的枚举很easy,就像注冊全局变量一样.我们使用枚举名称作为命名空间,来避免注冊的枚举发生冲突.注冊的枚举存储在全局环境(线程环境)中. 当在Lua Code中訪问枚举时,通过名称来訪问相应的值. sample_9.cpp   c++代码例如以下: //在Lua Code中注冊的enum,为了避免冲突,以名称作为enumTable来存储 enum Week { Monday, Tuesday, Wednesday, Thursday, Friday, Satur

lua入门之二:c/c++ 调用lua及多个函数返回值的获取

当 Lua 调用 C 函数的时候,使用和 C 调用 Lua 同样类型的栈来交互. C 函数从栈中获取她的參数.调用结束后将返回结果放到栈中.为了区分返回结果和栈中的其它的值,每一个 C 函数还会返回结果的个数(the  function  returns  (in  C)  the  number  of  results  it  is leaving on the stack.). // luacallcpp.cpp : 定义控制台应用程序的入口点. // #include "stdafx.