[Lua] Save the status in the C function-registry, Environment table, and upvalue
What is the Save status in the C function? For example, you now use Lua to call the C function Func1, but some data in Func1 is saved after the call for future use. The data is the so-called state, that is, what we need to save. Some people will say that when Lua calls C, it returns all the States to be saved to Lua. when calling the next function, it will pass in the desired state as a parameter, yes, it is a solution, but it is very troublesome. Method 1: Registry; Method 2: Environment; Method 3: upvalue.
The Registry is a global table that can only be accessed by C code. Generally, you can use it to save the data that needs to be shared among several modules;
However, if you need to save the private data of a module, you should use the environment. Like the Lua function, each C function has its own environment table. Generally, all functions in a module share the same environment table, so that they can share data.
Finally, the C function can also have upvalue, which is a Lua value associated with a specific function.
The Registry is always located on a "pseudo Index", which is defined by LUA_REGISTRYINDEX. A pseudo index is like an index in a stack, but its associated values are not in the stack. What do you think of after this sentence? In C ++, the new space is used to open up the space on the stack, but the variables pointing to the stack are stored on the stack. The pseudo index is similar to this. Most functions in Lua API can accept pseudo indexes, but functions like lua_remove and lua_insert can only use normal indexes.
The Registry is a normal Lua table that can be indexed using any Lua value (except nil.
# Include
Using namespace std; # include
Void registryTestFunc (lua_State * L) {lua_pushstring (L, "Hello"); lua_setfield (L, LUA_REGISTRYINDEX, "key1"); lua_getfield (L, LUA_REGISTRYINDEX, "key1 "); printf ("% s \ n", lua_tostring (L,-1); // The output is: Hello} int main () {lua_State * L = luaL_newstate (); registryTestFunc (L); lua_close (L); return 0 ;}
The environment table starts from 5.1 and all C Functions registered in Lua have their own environment table. A function can access its environment table through a pseudo index like accessing the registry. The pseudo index of the Environment table is LUA_ENVIRONINDEX.
This method of using the environment is similar to that of using the environment in the Lua module. It creates a new table for the module first, and then shares the table with all functions in the module. However, a setfenv function is used in Lua, while in Module C, the function sets table to LUA_ENVIRONINDEX.
# Include
Using namespace std; # include
Int setValue (lua_State * L) {luaL_checkstring (L,-1); lua_pushvalue (L,-1); lua_setfield (L, LUA_ENVIRONINDEX, "key1"); return 0 ;} int getValue (lua_State * L) {lua_getfield (L, LUA_ENVIRONINDEX, "key1"); return 1 ;}static luaL_Reg myfuncs [] ={{ "setValue", setValue }, {"getValue", getValue}, {NULL, NULL}; extern "C" _ declspec (dllexport) int luaopen_testenv (lua_State * L) {lua_newtable (L ); // create a new table for Environment lua _ Replace (L, LUA_ENVIRONINDEX); // replace the new table created and pushed into the stack with the Environment table of the current module. LuaL_register (L, "testenv", myfuncs); return 1; // This registration function requires two more lines of code than the previously written registration function. Create a new table first, call lua_replace to make the new table an environment table. Then, when luaL_register is called, all newly created functions will inherit the current environment .}
Content of the test. lua File
Require "testenv" local fun1 = function () local var = "Hello, world !!! "Testenv. setValue (var) print (testenv. getValue () -- output Hello, world !!! Endxpcall(fun,print+ OS .exe cute ("pause ")
Set the value to the Module Environment table. And then extract it from it. This is similar to the registry mentioned above. Although the environment may be used to replace the registry, if you do not need to share data between different modules, try not to use the registry. References created using the environment are only visible in this module, this reduces the scope of data use, reduces the possibility of data error correction, and increases data security. Upvalueupvalue is associated with a specific function. We can simply understand it as a static variable in the function.
The Registry provides the storage of global variables, the environment provides the storage of module variables, and the upvalue mechanism implements a mechanism similar to the static variables in C language. This upvalue mechanism allows us to define a variable that is visible only in a specific function. Whenever you create a function in Lua, You can associate any number of upvalue with this function. Each upvalue can save a Lua value. In the future, when calling this function, you can use pseudo indexes to access these upvalue. The association between these C Functions and upvalue is called closure (also called closure, a familiar name ). A c closure is similar to a Lua closure. Closure can use the same function code to create multiple closure. Each closure can have different upvalue.
# Include
Using namespace std; # include
Int counter (lua_State * L) {// obtain the value of the first upvalue. Int val = lua_tointeger (L, lua_upvalueindex (1); // press the result to the stack. Lua_pushinteger (L, ++ val); // assign a value to the top of the stack to facilitate subsequent replacement operations. Lua_pushvalue (L,-1); // This function replaces the data at the top of the stack with the value in upvalue (1. At the same time, the top data of the stack is popped up. Lua_replace (L, lua_upvalueindex (1); // the data in the middle of lua_pushinteger (L, ++ value) is retained in the stack and returned to Lua. Return 1;} int newCounter (lua_State * L) {// press the initial value 0 of A upvalue. This function must be called before lua_pushcclosure. Lua_pushinteger (L, 0); // press into the closure function. Parameter 1 indicates the number of upvalue of the closure function. The return value of this function. The closure function is always at the top of the stack. Lua_pushcclosure (L, counter, 1); return 1;} static luaL_Reg myfuncs [] ={{ "counter", counter}, {"newCounter", newCounter}, {NULL, NULL }}; extern "C" _ declspec (dllexport) int luaopen_testupvalue (lua_State * L) {luaL_register (L, "testupvalue", myfuncs); return 1 ;}
Content of the test. lua File
Require "testupvalue" local fun = function () func = testupvalue. newCounter (); print (func (); func = testupvalue. newCounter (); print (func (); -- [the output result is: 1 2 3 1 2 3 --]]endxpcall(fun,print+ OS .exe cute ("pause ")