2017-09-03 2 views
2

Créons un simple module C pour Lua 5.3 avec un int global:Lua partagé exemple upvalue en C

static int l_test(lua_State *L){ 
    int Global = lua_tointeger(L, lua_upvalueindex(1)); 
    Global++; 
    lua_pushinteger(L, Global); 
    lua_pushvalue(L, -1); 
    lua_replace(L, lua_upvalueindex(1)); 
    //lua_pushnumber(L, Global); 
    return 1; 
} 

static int l_anotherTest(lua_State *L){ 
    int Global = lua_tointeger(L, lua_upvalueindex(1)); 
    Global++; 
    Global++; 
    lua_pushinteger(L, Global); 
    lua_pushvalue(L, -1); 
    lua_replace(L, lua_upvalueindex(1)); 
    //lua_pushnumber(L, Global); 
    return 1; 
} 

static const struct luaL_Reg testLib [] = { 
    {"test", l_test}, 
    {"anotherTest", l_anotherTest}, 
    {NULL, NULL} 
}; 

int luaopen_testLib(lua_State *L){ 
    luaL_newlibtable(L, testLib); 
    lua_pushinteger(L, 1); 
    luaL_setfuncs(L, testLib, 1) ;  
    return 1; 
} 

Cela fonctionne presque, mais quand j'appelle ces deux fonctions de Lua comme ceci:

local testLib = require "testLib" 
print(testLib.test()) 
print(testLib.anotherTest()) 

La deuxième impression doit être 4, mais elle affiche un 3. Qu'est-ce que je fais encore de mal?

+1

Pour initialiser le upvalue, vous devez pousser sa valeur initiale sur la pile juste avant d'appeler 'setfuncs'. Pour accéder à la valeur up de 'l_test', vous devez utiliser' lua_upvalueindex (1) 'pour obtenir le pseudo-index de la pile où se trouve cette valeur. –

+0

Merci pour l'indice. J'ai mis à jour la question. Il y a encore quelque chose qui manque ici. Pouvez-vous m'aider? – user1511417

+0

Utilisez la macro 'NULL' si vous voulez une constante de pointeur NULL. L'utilisation de l'entier '0' est un héritage trompeur. – Olaf

Répondre

3

Les valeurs supérieures des fermetures C ne sont pas partagées, seules les valeurs supérieures des fermetures Lua le sont. Chaque fermeture C contient directement ses valeurs supérieures (voir here). Si vous souhaitez partager des valeurs pour deux fermetures C ou plus, utilisez une seule table commune comme valeur supérieure dans chacune d'entre elles et placez-y vos valeurs partagées, ou utilisez plutôt le registre pour vos données partagées.

Quelque chose comme ce qui suit devrait faire ce que vous voulez:

#include <lua.h> 
#include <lauxlib.h> 


/* getint and setint may only be called from Lua C functions that 
* have the shared table as upvalue 1. 
*/ 

static int getint(lua_State *L){ 
    int v = 0; 
    lua_getfield(L, lua_upvalueindex(1), "myint"); 
    v = lua_tointeger(L, -1); 
    lua_pop(L, 1); /* remove integer from stack */ 
    return v; 
} 

static void setint(lua_State *L, int v){ 
    lua_pushinteger(L, v); 
    lua_setfield(L, lua_upvalueindex(1), "myint"); 
} 


static int l_test(lua_State *L){ 
    int Global = getint(L); 
    Global++; 
    setint(L, Global); 
    lua_pushinteger(L, Global); 
    return 1; 
} 

static int l_anotherTest(lua_State *L){ 
    int Global = getint(L); 
    Global++; 
    Global++; 
    setint(L, Global); 
    lua_pushinteger(L, Global); 
    return 1; 
} 

static const struct luaL_Reg testLib [] = { 
    {"test", l_test}, 
    {"anotherTest", l_anotherTest}, 
    {NULL, NULL} 
}; 

int luaopen_testLib(lua_State *L){ 
    luaL_newlibtable(L, testLib); 
    lua_newtable(L); 
    lua_pushinteger(L, 1); 
    lua_setfield(L, -2, "myint"); 
    luaL_setfuncs(L, testLib, 1); 
    return 1; 
} 
+0

@siffiejoe - 'luaL_setfuncs' vous permet de SHARE upvalues ​​parmi toutes les fonctions C d'enregistrement. C'est ce que l'OP essaie de réaliser. –

+2

@EgorSkriptunoff: Toutes les fermetures C de l'appel 'luaL_setfuncs' auront les mêmes valeurs supérieures par la suite, mais ces valeurs ne sont pas ** partagées, c'est-à-dire que la modification des valeurs d'une fermeture n'a aucun effet sur les valeurs supérieures des autres fermetures. sauf * si vous mutez des valeurs qui sont passées par référence comme des tables, des données d'utilisateur, etc. (toutes les fermetures auront des références séparées à la même table/userdata/...). – siffiejoe

+1

J'ai trouvé un vieux fil de discussion pour vous: http://lua-users.org/lists/lua-l/2006-08/msg00189.html – siffiejoe