作者:糖果

Exposing C++ functions to Lua takes place through a process called function binding. Any bound functions exposed to Lua become accessible either as a global function or as a function available through a package. Packages in Lua are similar to namespaces in C++ and are implemented as a global table within Lua.

通过暴漏C函数给Lua的过程,叫做函数绑定。任何绑定函数暴漏给Lua成为一个可访问的全局函数,或是作为可用的包函数。Lua中的Packages(包)类似于C中的命名空间,作为一个类似全局表被实现的。

Function binding

Any function exposed to Lua must fit the lua_CFunction declaration. A lua_CFunction declaration takes in the Lua virtual machine and returns the number of return values pushed onto the Lua stack:

Function binding(函数绑定)

任何函数暴漏给Lua对应的必须要有lua_CFunction声明。lua_CFunction声明取得Lua虚拟机和返回数字的返回到栈上。

lua.h

typedef int (*lua_CFunction) (lua_State *L);

例如,C++的GetRadius函数暴漏在沙盒中,是被定义在LuaScriptBingdings.h头文件中的,如下:

LuaScriptBindings.h

int Lua_Script_AgentGetRadius(lua_State* luaVM);
The actual function implementation is defined within the LuaScriptBindings.cpp file and contains the code for retrieving and pushing values back to the stack. The GetRadius function expects an agent pointer as the first and only parameter from Lua and returns the radius of the agent. The Lua_Script_AgentGetRadius function first checks the stack for the expected parameter count and then retrieves the userdata off the stack through a helper function within the AgentUtilities class. An additional helper function performs the actual work of calculating the agent’s radius and pushes the value back onto the stack:
实际的函数实现是别定义在LuaScriptBindings.cpp文件中,和接受与推送值入栈的代码。GetRadius函数期待

一个"agent"指针作为唯一的一个从lua来的参数,并且将"agent"返回。Lua_Script_AgentGetRadius函数首先检查栈中期待的参数个数和接受的“userdata”(用户数据) 通过AgentUilities类中的助手函数出栈。另外的一个助手函数执行实际的agent半径计算工作,然后将值入栈。

LuaScriptBindings.cpp

int Lua_Script_AgentGetRadius(lua_State* luaVM)

{

if (lua_gettop(luaVM) == 1)

{

Agent* const agent = AgentUtilities::GetAgent(

luaVM, 1);

return AgentUtilities::PushRadius(luaVM, agent);

}

return 0;

}
To bind the function to Lua, we define a constant array that maps the function’s name within Lua to the C function that should be called. The array of function mappings must always end with a null luaL_Reg type struct. Lua uses a null luaL_Reg type struct as a terminator when processing the function map:

绑定函数到Lua,我们定义了一个常量数组映射,从Lua中的函数名称和应该被调用的C函数。这个函数数组映射,比如总是一个以null结尾的Lual_Reg类型的结构体。当处理函数map时,Lua使用null做为luaL_Reg类型结构的结束标记。

AgentUtilities.cpp

const luaL_Reg AgentFunctions[] =

{

{ "GetRadius", Lua_Script_AgentGetRadius },

{ NULL, NULL }

};
The actual function binding to the Lua virtual machine takes place in the luaL_register helper function. The register function binds the table of function names to their corresponding C callback function. The package name is specified at this step and will be associated with each function within the mapping:

实际的函数绑定虚拟机发生在luaL_register助手函数。 助手函数绑定了函数名table表,到他们对应C回调函数。包名在这一步指定,并且在映射中关联到每个函数。

AgentUtilities.cpp

void AgentUtilities::BindVMFunctions(lua_State* const luaVM)

{

luaL_register(luaVM, "Agent", AgentFunctions);

}

Note(注意)

If NULL is passed in as the package name, Lua requires that a table be at the top of the Lua stack. Lua will add the C functions to the Lua table at the top of the stack.
如果包名传成空,Lua会从栈顶导入映射表。Lua会添加C函数到栈顶的Lua table表中。

本文译自David Young《Lua游戏AI开发指南》一书。

PS:转载到其它平台请注明作者姓名及原文链接。