三、在LUA腳本中調用C/C++函數
可以被Lua函數調用的C函數必須遵循的協議(這個協議定義了參數和結果的傳遞方式):C函數從LUA棧上按直接的順序獲取參數(第一個參數首先被push)。所以當C函數開始執行時,lua_gettop(L)返回這個C函數的參數個數。第一個參數(如果有的話)索引爲1,而最後一個參數的索引爲lua_gettop(L)。爲了將結果傳遞到LUA中,C函數將結果以直接的順序push到棧上,並以結果的個數作爲自己的返回值。棧上除結果以外的其它值將自動地被LUA以適當的方式刪除掉。與LUA函數一樣,被LUA調用的C函數也可能返回多個值到棧上。可以被Lua函數調用的C函數的類型:
typedef int (*lua_CFunction) (lua_State *L);
下面是一個Lua函數調用C函數的例子
TestCFunc.lua的內容如下:
function LuaCallMyCMax()
local tmp = MyCMax(10, 11, 12)
local str = "call MyCMax(10, 11, 12) in LUA and max number is "
print ( (str)..(tmp) )
return tmp
end
test.h的內容如下:
float max(float a, float b)
{
return (a>b ? a : b);
}
float max(float a, float b, float c)
{
float tmp = (a>b ? a : b);
return ( tmp>c ? tmp : c);
}
int _cdecl MyCMax(lua_State* L)
{
int n = lua_gettop(L); // number of arguments
int i;
for (i = 1; i <= n; i++) {
if (!lua_isnumber(L, i)) {
lua_pushstring(L, "incorrect argument");
lua_error(L);
}
}
lua_Number tmp = 0;
if (1 == n) {
tmp = lua_tonumber(L, 1);
} else if (2 == n) {
tmp = max(lua_tonumber(L, 1), lua_tonumber(L, 2));
}
else if (3 <= n) {
tmp = max(lua_tonumber(L, 1), lua_tonumber(L, 2), lua_tonumber(L, 3));
} else {
return 0;
}
lua_pushnumber(L, tmp); // first result
return 1; // number of results
}
test.cpp的內容如下:
// …omitted…
lua_pushcfunction(L, MyCMax); // push MyCMax -fuction
lua_setglobal(L, "MyCMax"); // registry MyCMax() as a global MyCMax in LUA
//或只一句lua_register(L, "MyCMax", MyCMax);
lua_getglobal(L, "LuaCallMyCMax");
lua_pcall(L, 0, 1, 0);
std::cout << "call LuaCallMyCMax() in C and result is "
<< lua_tonumber(L, -1)
<< std::endl;
lua_pop(L,1);
// …omitted…
Lua函數調用C函數的過程:
(1) 聲明並定義一個類型爲lua_CFunction的C函數 (eg. MyCMax)
(2) 將(1)定義的C函數(指針)入棧
(3) 調用LUA庫的註冊函數(eg. lua_setglobal宏) 以某name註冊C函數
(4) 從LUA中以註冊名name(eg. MyCMax,註冊時可另取)調用C函數