2010-04-22 7 views
11

I ont une fonction de C (A) test_callback accepter un pointeur vers une fonction (B) en tant que paramètre et A sera "callback" B.comment callback une fonction de lua de la fonction de courant alternatif

//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 

Maintenant, Je veux envelopper test_callback afin qu'ils puissent être appelés à partir de lua, supposons que le nom est lua_test_callback, et aussi le paramètre d'entrée à ce serait une fonction lua. Comment devrais-je atteindre cet objectif?

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 " 

EDIT:

This link fournissent un moyen de stocker la fonction de rappel pour une utilisation ultérieure.

//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 

Répondre

9

Je ne suis pas sûr que je comprends votre question, si vous demandez quel serait lua_test_callback regard en C, il devrait être quelque chose comme ça

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 
} 

Vous ne pouvez pas simplement envelopper test_callback, vous devez entièrement implémentation différente pour appeler les fonctions Lua.

(edit: changé lua_call-lua_pcall comme suggéré par Nick I toujours évité toute erreur de manipulation par souci de concision.)

+2

Il est préférable d'utiliser lua_pcall qui poussera une erreur sur la pile plutôt que de simplement s'écraser. –

+0

Bon exemple correct. Mais en pratique, il est préférable d'utiliser une interface commune, bien testée, malgré l'écriture de telles fonctions lua_test_callback() encore et encore. –

3

Le moyen pratique de faire des appels à différentes fonctions Lua avec des signatures différentes:

A. Marque une classe qui maintiendra l'état de Lua en toute sécurité et fournira une interface facile. N'écrivez pas des appels aux fonctions de Lua à partir de zéro (avec beaucoup de travail push/pop et affirme) encore et encore - il suffit d'utiliser cette interface de classe. C'est une approche sûre, rapide et pratique.

B. Définir poussoirs et les méthodes de pop push/pop arguments sur/à partir de la pile 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. définir des fonctions pour appeler des fonctions 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. Définir le gestionnaire d'erreur (lua_pcall appellera cette fonction Lua si erreur)

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