2010-04-22 59 views
11

一個Lua函數我有一個C函數(A)test_callback接受指針的功能(B)作爲參數和A將 「回調」 B.如何回調從交流功能

//typedef int(*data_callback_t)(int i); 
int test_callback(data_callback_t f) 
{ 
    f(3); 
} 


int datacallback(int a) 
{ 
    printf("called back %d\n",a); 
    return 0; 
} 


//example 
test_callback(datacallback); // print : called back 3 

現在,我想包裝test_callback,以便可以從lua調用它們,假設名稱爲lua_test_callback;並且其輸入參數爲lua函數。我應該如何實現這一目標?

function lua_datacallback (a) 
    print "hey , this is callback in lua" ..a 
end 


lua_test_callback(lua_datacallback) //expect to get "hey this is callback in lua 3 " 

編輯:

This link提供一種方式來存儲供以後使用的回調函數。

//save function for later use 
callback_function = luaL_ref(L,LUA_REGISTRYINDEX); 


//retrive function and call it 
lua_rawgeti(L,LUA_REGISTRYINDEX,callback_function); 
//push the parameters and call it 
lua_pushnumber(L, 5); // push first argument to the function 
lua_pcall(L, 1, 0, 0); // call a function with one argument and no return values 

回答

9

我不知道我理解你的問題,如果你問什麼會lua_test_callback看在C,它應該是這樣的

int lua_test_callback(lua_State* lua) 
{ 
    if (lua_gettop(lua) == 1 && // make sure exactly one argument is passed 
     lua_isfunction(lua, -1)) // and that argument (which is on top of the stack) is a function 
    { 
     lua_pushnumber(lua, 3); // push first argument to the function 
     lua_pcall(lua, 1, 0, 0); // call a function with one argument and no return values 
    } 
    return 0; // no values are returned from this function 
} 

你不能只是包裝test_callback,則需要完全不同的實現調用Lua函數。

(編輯:改變lua_calllua_pcall由尼克的建議我還是省略任何錯誤處理的簡潔。)

+2

它是優選使用lua_pcall這將推動錯誤到堆棧,而不是僅僅崩潰。 – 2010-04-22 14:10:44

+0

不錯的例子。但在實踐中,儘管一次又一次地寫入這樣的lua_test_callback()函數,但使用通用的,經過良好測試的接口會更好。 – 2010-04-22 18:12:48

3

做用不同的簽名不同Lua函數調用的便捷方式:

答。一個能夠安全地維護Lua狀態的類,並且將提供簡單的界面。不要一次又一次地從頭調用Lua函數(大量推/拉工作並斷言) - 只需使用此類接口即可。這是安全,快捷和方便的方法。

B.定義push和pop方法推/彈出參數上/從Lua堆棧:

template<typename T> void push(T argument); 
template<typename T> void get(const int index, T& return_value); 

template<> void State::push(bool arg) 
{ 
    lua_pushboolean (lua_state, arg ? 1 : 0); 
} 

template<> void State::push(float arg) 
{ 
    lua_pushnumber (lua_state, arg); 
} 

template<> void State::push(int arg) 
{ 
    lua_pushnumber (lua_state, arg); 
} 

// ... 
template<> void State::get(const int index, bool& ret) 
{ 
     if (!lua_isboolean(lua_state, index)) { ... } 
     ret = lua_toboolean(lua_state, index) != 0; 
} 

C.定義功能調用Lua函數:

// Call function that takes 1 argument and returns nothing 
template <typename A1> 
void call(const char * funcName, A1 arg1) 
{ 
    lua_getfield (lua_state, LUA_GLOBALSINDEX, funcName);  // push global function f on stack 
    push (arg1);           // push first argument on stack 
    assert_call( lua_pcall(lua_state, 1, 0, this->err_h));  // call function taking 1 argument and getting no return value 
} 


// call function that takes 2 argument and returns 1 value 
template <typename R1, typename A1, typename A2> 
void callr1(const char * funcName, R1& res, A1 arg1, A2 arg2) 
{ 
    lua_getfield (lua_state, LUA_GLOBALSINDEX, funcName);  // push global function f on stack 
    push (arg1);           // push first argument on stack 
    push (arg2); 
    assert_call( lua_pcall(lua_state, 2, 1, this->err_h));  // call function taking 2 arguments and getting 1 return value 
    get (-1, res); 
    lua_pop(lua_state, 1); 
} 

D.設置錯誤處理程序(如果錯誤,lua_pcall將調用此Lua函數)

void setErrorHandler(const char * funcName) 
{ 
    lua_getfield (lua_state, LUA_GLOBALSINDEX, funcName); 
    this->err_h = lua_gettop(lua_state); 
}