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 luaL_openlib was replaced by luaL_register.

其实在Lua中注册C code函数来扩展lua,最简单,最直接的学习是从Lua 源代码本身。

本着简单原则,在Lua 源代码中  lmathlib.c 数学库,loslib.c 系统库,lbaselib.c 基本库最为简单。

1、在Lua 中注册C code函数必须遵循一定的准则。在Lua 5.1 Reference Manual  中typedef int (*lua_CFunction) (lua_State *L); 详细说明如下:

In order to communicate properly with Lua, a C function must use the following protocol, which defines the way parameters and results are passed:

a C function receives its arguments from Lua in its stack in direct order (the first argument is pushed first).

So, when the function starts, lua_gettop(L) returns the number of arguments received by the function.

The first argument (if any) is at index 1 and its last argument is at index
lua_gettop(L)
.

To return values to Lua, a C function just pushes them onto the stack, in direct order (the first result is pushed first), and returns the number of results.

Any other value in the stack below the results will be properly discarded by Lua.

Like a Lua function, a C function called by Lua can also return many results.

为了和Lua 进行互通,C函数必须遵循如下规则来接受Lua Code传递的参数和传递结果给Lua Code:

当一个Lua Code调用了已经注册的C code函数,C函数从虚拟栈中接受到参数。当在C code开始时,调用lua_gettop(L)将获取Lua Code传递参数的个说。

第一个被传递到C code函数的参数正向索引为1,栈顶索引为lua_gettop(L).

为了把结果返回到Lua Code中,在C函数中可以把结果值压入虚拟栈。同时C函数的返回值必须是一个整数。代表着返回值的个数。在返回值下面的数据都将被丢弃。

2、从最简单的lmathlib.c的源代码分析开始学习在Lua中定义C code函数。

2.1在lua.h中定义了函数指针:typedef int (*lua_CFunction) (lua_State *L); 所有在Lua中定义的函数形式必须和这个一样。 返回值int ,表示从C函数返回到Lua Code结果的数量。

2.2  真正注册C函数的关键Lua C API为void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n); 这里先提及以后详细介绍。其余注册函数最终都是包裹着这个函数。

2.3 对lmathlib.c部分代码进行分析

/*
** Open math library 注册数学库
*/
LUALIB_API int luaopen_math (lua_State *L)
{
  //通过luaL_register 把libname和lib一次性注册到_G[math] Table中,同时把_G[math] Table压入到虚拟栈顶
  luaL_register(L, LUA_MATHLIBNAME, mathlib);
  //压入PI 数值到虚拟栈顶
  lua_pushnumber(L, PI);
  //设置_G[math][pi]=PI
  lua_setfield(L, -2, "pi");
  lua_pushnumber(L, HUGE_VAL);
  lua_setfield(L, -2, "huge");
  //在版本演化中,为了兼容低版本
#if defined(LUA_COMPAT_MOD)
  lua_getfield(L, -1, "fmod");
  lua_setfield(L, -2, "mod");
#endif
  return 1;
}
static const luaL_Reg mathlib[] = {
  {"abs",   math_abs},
  {NULL, NULL}
};

最后的NULL必须有,标记着指针数组的结束。

//取绝对值函数
//所有在Lua Code中注册的函数必须为lua_CFunction函数指针
//因为函数名称就是函数指针
static int math_abs (lua_State *L)
{
  //当lua Code调用math.abs(-1)函数时,参数-1被压入栈顶
  //利用ANSC C提供的标准函数库来对栈顶元素进行求绝对值
  //然后利用lua_pushnumber()函数把结果压入虚拟栈
  lua_pushnumber(L, fabs(luaL_checknumber(L, 1)));
  //最后返回值标记着虚拟栈中数据的数量
  return 1;
}
local a =math.abs(-1)
print("a="..a)

当math.abs(-1) Lua Code函数执行时,Lua虚拟栈就会调用math_abs(lua_State *L) 函数,同时传递-1参数到虚拟栈顶部。

3  对Lua  loslib.c 源代码部分进行分析,

//os.time ([table])
//Returns the current time when called without arguments, or a time representing the date and time specified by the given table.
static int os_time (lua_State *L)
{
  time_t t;
  //当os.time()函数使用无参数调用时,获取当前时间
  if (lua_isnoneornil(L, 1))  /* called without args? */
    t = time(NULL);  /* get current time */
  else
  {
    struct tm ts;
	//否则获取虚拟栈上面table数据结构
    luaL_checktype(L, 1, LUA_TTABLE);
    lua_settop(L, 1);  /* make sure table is at the top */
	//获取结构中的字段,如果获取不到,设置不同的默认值
    ts.tm_sec = getfield(L, "sec", 0);
    ts.tm_min = getfield(L, "min", 0);
    ts.tm_hour = getfield(L, "hour", 12);
    ts.tm_mday = getfield(L, "day", -1);
    ts.tm_mon = getfield(L, "month", -1) - 1;
    ts.tm_year = getfield(L, "year", -1) - 1900;
    ts.tm_isdst = getboolfield(L, "isdst");
	//转换成时间戳
    t = mktime(&ts);
  }
  //判断是否越界,然后把结果值压入虚拟栈返回给Lua Code函数
  if (t == (time_t)(-1))
    lua_pushnil(L);
  else
    lua_pushnumber(L, (lua_Number)t);
  return 1;
}
时间: 2024-10-25 04:44:24

Lua 与C/C++ 交互系列: Lua调用C/C++函数(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++函数(4-1)

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

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++ 交互系列: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.