注册c函数给lua使用
#注册C函数给lua
lua中存在 typedef int (*lua_CFunction) (lua_State *L); C 函数的类型。
为了正确的和 Lua 通讯, C 函数必须使用下列协议。 这个协议定义了参数以及返回值传递方法: C 函数通过 Lua 中的栈来接受参数, 参数以正序入栈(第一个参数首先入栈)。 因此,当函数开始的时候, lua_gettop(L) 可以返回函数收到的参数个数。 第一个参数(如果有的话)在索引 1 的地方, 而最后一个参数在索引 lua_gettop(L) 处。 当需要向 Lua 返回值的时候, C 函数只需要把它们以正序压到堆栈上(第一个返回值最先压入), 然后返回这些返回值的个数。 在这些返回值之下的,堆栈上的东西都会被 Lua 丢掉。 和 Lua 函数一样,从 Lua 中调用 C 函数也可以有很多返回值
我们可以使用luaL_Reg 构建一个数组,将函数类型为lua_CFunction 的函数快速注册给lua。
typedef struct luaL_Reg {
const char *name;
lua_CFunction func;
} luaL_Reg;
void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup);
用于 luaL_setfuncs 注册函数的数组类型。 name 指函数名,func 是函数指针。 任何 luaL_Reg 数组必须以一对 name 与 func 皆为 NULL 结束。
static int AddNumber(lua_State* pl)
{
lua_pushnumber(L, 1+2);
return 1;
}
static struct luaL_Reg arrayFunc[] =
{
{"AddNumber", AddNumber},
{NULL, NULL},
};
luaL_setfuncs(L, ObjFunc, 0);
但是这种方式虽然简单,但是不能传递参数。下面是一种可以注册复杂c函数的方式。使用了一些模板的相关功能。其中CAnyValue是一种简单的万能变量的实现方式,再以后的文章中我会详细介绍一下。
extern "C"
{
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
}
#include "CAnyValue.h"
#include "stdio.h"
#include "string.h"
#define INIT_VALUE(__type, __value) \
__type __value; \
InitValue(__value);
void InitValue(int& v)
{
v = 0;
}
void InitValue(double& v)
{
v = 0.00000f;
}
void InitValue(bool& v)
{
v = true;
}
void InitValue(char*& v)
{
v = NULL;
}
int GetLuaParam(lua_State* L, int nParamCnt, CAnyValue* v)
{
for (int i = 0; i < nParamCnt; i++)
{
int index = i - nParamCnt;
int n = lua_gettop(L);
if ((index > n) || (index < -n) || (index == 0))
return -1;
switch (lua_type(L, index))
{
case LUA_TNIL:
break;
case LUA_TNUMBER:
{
int temp = (int)lua_tonumber(L, index);
v->set(temp);
break;
}
case LUA_TSTRING:
{
char* temp = (char*)lua_tostring(L, index);
v->set(temp);
break;
}
case LUA_TBOOLEAN:
{
bool temp = (bool)lua_toboolean(L, index);
v->set(temp);
break;
}
default:
break;
}
v++;
}
return 1;
}
void Push(lua_State* L, int v)
{
lua_pushnumber(L, v);
}
void Push(lua_State* L, bool v)
{
lua_pushboolean(L, v);
}
void Push(lua_State* L, char* v)
{
lua_pushstring(L, v);
}
template<typename T>
int Call(lua_State* L, T fn)
{
return (T)(*fn)(L);
}
template<>
int Call(lua_State* L, int(*fn)(lua_State*))
{
return (*fn)(L);
}
template<typename P1>
int Call(lua_State* L, int(*fn)(lua_State*, P1))
{
CAnyValue anyValue[1];
P1 arg1;
InitValue(arg1);
GetLuaParam(L, 1, &anyValue[0]);
anyValue[0].get(arg1);
return (*fn)(L, arg1);
}
template<typename P1, typename P2>
int Call(lua_State* L, int(*fn)(lua_State*, P1, P2))
{
CAnyValue anyValue[2];
P1 arg1;
P2 arg2;
InitValue(arg1);
InitValue(arg2);
GetLuaParam(L, 2, anyValue);
anyValue[0].get(arg1);
anyValue[1].get(arg2);
return (*fn)(L, arg1, arg2);
}
template<typename P1, typename P2, typename P3>
int Call(lua_State* L, int(*fn)(lua_State*, P1, P2, P3))
{
CAnyValue anyValue[3];
P1 arg1;
P2 arg2;
P3 arg3;
InitValue(arg1);
InitValue(arg2);
InitValue(arg3);
GetLuaParam(L, 3, anyValue);
anyValue[0].get(arg1);
anyValue[1].get(arg2);
anyValue[2].get(arg3);
return (*fn)(L, arg1, arg2, arg3);
}
template<typename P1, typename P2, typename P3, typename P4>
int Call(lua_State* L, int(*fn)(lua_State*, P1, P2, P3, P4))
{
CAnyValue anyValue[4];
P1 arg1;
P2 arg2;
P3 arg3;
P4 arg4;
InitValue(arg1);
InitValue(arg2);
InitValue(arg3);
InitValue(arg4);
GetLuaParam(L, 4, anyValue);
anyValue[0].get(arg1);
anyValue[1].get(arg2);
anyValue[2].get(arg3);
anyValue[3].get(arg4);
return (*fn)(L, arg1, arg2, arg3, arg4);
}
template<typename F>
int GlobalRegCFunc(lua_State* L)
{
void** pFunc = (void**)lua_touserdata(L, lua_upvalueindex(1));
return Call(L, (F)(*pFunc));
}
template<typename F>
void Register(lua_State* L, const char* funcName, F fn)
{
unsigned char* pFunc = (unsigned char*)lua_newuserdata(L, sizeof(F));
memcpy(pFunc, &fn, sizeof(F));
lua_pushcclosure(L, GlobalRegCFunc<F>, 1);
lua_setglobal(L, funcName);
}
int Add(lua_State* L, int a)
{
int nRetCount = 0;
lua_pushnumber(L, a+1);
nRetCount++;
return nRetCount;
}
int Plus(lua_State* L, int a, int b, char* connect)
{
int nRetCount = 0;
lua_pushnumber(L, a + b);
nRetCount++;
printf("%s\n", connect);
return nRetCount;
}
int main()
{
lua_State* L = luaL_newstate();
if (!L)
return 0;
luaL_openlibs(L);
Register(L, "Add", Add);
Register(L, "Plus", Plus);
int ret = luaL_loadfile(L, "test.lua");
if (ret != 0)
{
printf("%s\n", lua_tostring(L, -1));
lua_pop(L, 1);
}
ret = lua_pcall(L, 0, 0, 0);
if (ret != 0)
{
printf("%s\n", lua_tostring(L, -1));
lua_pop(L, 1);
}
return -1;
}