用C C++ 编写lua模块的一般模式

作为一种嵌入式语言,lua提供了一套完备的 C API来帮助 lua 与 宿主程序进行交互。因此使用 C 或者 C++ 来为lua编写模块是很容易的。

看一下lua (5.1) 中对 string 模块的封装源码 lstrlib.c

在 lstrlib.c 最后有这样的代码


/**
    将函数名与实际调用函数记录在一个 struct 中,并组成一个数组
    --- 有点 lua 代码的赶脚 ---
**/
static const luaL_Reg strlib[] = {
  {"byte", str_byte},
  {"char", str_char},
  {"dump", str_dump},
  {"find", str_find},
  {"format", str_format},
  {"gmatch", gmatch},
  {"gsub", str_gsub},
  {"len", str_len},
  {"lower", str_lower},
  {"match", str_match},
  {"rep", str_rep},
  {"reverse", str_reverse},
  {"sub", str_sub},
  {"upper", str_upper},
  {"pack", str_pack},
  {"packsize", str_packsize},
  {"unpack", str_unpack},
  {NULL, NULL}
};

/**
    这里是对创建的lib 元表进行后续加工,具体可以看源代码
**/
static void createmetatable (lua_State *L) {
    ....
}


/*
** Open string library
** 这里是string 库的主入口
*/
LUAMOD_API int luaopen_string (lua_State *L) {
  luaL_newlib(L, strlib); // 创建一个 lib 元表,并将 strlib 5.2之前使用luaL_register(L, "modulename", modulename); 中的函数名与函数放到表中
  createmetatable(L); // 对创建的 lib 元表进行再次处理
  return 1;
}

类似的代码也出现再了 loadlib.c(package模块)、loslib.c(os 模块)

因此可以总结出 lua 模块的编写方式

  • 1、定义 C/C++ 中的 函数
  • 2、定义 luaL_Reg 数组
  • 3、创建 lib 元表。这里需要注意 在 5.2 之后的版本中可以直接使用 luaL_newlib,而之前的版本需要使用 luaL_register(L, "modulename", modulename);

C/C++ 与 lua 类型

将数据传入lua接口

/**
    向栈中压入 NULL
**/
LUA_API void  (lua_pushnil) (lua_State *L);

/**
    向栈中压入 double
**/
LUA_API void  (lua_pushnumber) (lua_State *L, lua_Number n);

/**
    向栈
**/
LUA_API void  (lua_pushinteger) (lua_State *L, lua_Integer n);

/**
    将字符串s的指定长度len压入栈中
**/
LUA_API void  (lua_pushlstring) (lua_State *L, const char *s, size_t l);

/**
    向栈中压入一个字符串
**/
LUA_API void  (lua_pushstring) (lua_State *L, const char *s);

/**
    向栈中压入字符串并格式化
**/
LUA_API const char *(lua_pushvfstring) (lua_State *L, const char *fmt,
                                                      va_list argp);
/**
    向栈中压入字符串并格式化
    使用可变参数进行格式化
**/
LUA_API const char *(lua_pushfstring) (lua_State *L, const char *fmt, ...);

/**
    向栈中压入一个C函数
**/
LUA_API void  (lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n);

/**
    将 b 作为布尔值压入栈中
**/
LUA_API void  (lua_pushboolean) (lua_State *L, int b);

/**
    将一个轻量用户数据压入栈中
**/
LUA_API void  (lua_pushlightuserdata) (lua_State *L, void *p);

/**
  "L"表示的线程入栈。如果这个线程是当前状态机的主线程的话,返回1。
**/
LUA_API int   (lua_pushthread) (lua_State *L);