Plus, C module writing (2)

Source: Internet
Author: User

Objective

In the further C module writing (1), we summarize the operation of array and string when Lua calls C function, and this article will focus on how to save state in C function.

What is it called in the C function to save the state? For example, you are now using LUA to invoke the C function Func1, but some of the data in Func1 is saved for later use after the call is finished. And that data is the so-called state, which is what we need to preserve. Depending on what is currently summarized, it is not possible to save the state in the C function. Someone will say, when Lua calls C, all the states that need to be saved are returned to Lua, and when the next function is called, the required state is passed in as a parameter, which is a good way, but it is troublesome. And here I will summarize 3 kinds of more convenient, but a little bit difficult to understand the method in the C function to save the state.

    • Method one: Registration form;
    • Method Two: environment;
    • Method Three: Upvalue.

The registry is a global table that can only be accessed by C code. In general, you can use it to hold data that needs to be shared among several modules, but if you need to save a module's private data, you should use the environment, like the LUA function, where each C function has its own environment table, and normally all functions within a module share the same environment table, This allows them to share data. Finally, the C function can also have upvalue,upvalue, which is a LUA value associated with a particular function. Now I'll start analyzing and summarizing. Let ' s go.

"Registration Form"

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 the value associated with it is not in the stack; What do you think of the end of the sentence? In C + +, using new to open space, this space is created on the heap, and the variables that point to the heap are stored on the stack. Pseudo-index is similar to this meaning. Most functions in the Lua API can accept pseudo-indexes, but functions such as lua_remove and Lua_insert can only use normal indexes.

The registry is a normal LUA table that can be indexed with any LUA value (except nil). For example, to get the value of key "Jellythink" in the registry, you can do this:

" Jellythink ");

Now there is a very difficult problem, because all C modules share the same registry, in order to avoid the use of conflicts, you must carefully select the value of key, in order to ensure the uniqueness of key, avoid conflicts, we recommend using UUID as the key value.

In the registry, do not use the number type key, because this key is reserved by the reference system. A reference system consists of a series of functions in a secondary library that can ignore how to create a unique key when storing value to a table. For example, the following call:

int r = lual_ref (L, Lua_registryindex);

A value is popped from the stack, and then the value is saved to the registry with a newly assigned integer key, and the integer key is returned. This key is referred to as a "reference".

Do you ask me what case to use the registry? The registry is a global table that can share data in multiple C modules, register a reference to a LUA value in a C module, and use this reference in other C modules. Light said no practice, goose over also pull wool, below an example, do the following test:

    1. Preparation of Cmodule and CModule2 two C modules;
    2. Lua calls Cmodule, passes in a table, registers in Cmodule, and prints the value in the table in CModule2;
    3. Lua calls Cmodule, passes in a function, registers in Cmodule, and calls the LUA function in CModule2;
    4. Lua calls Cmodule, passes in a string value, registers in Cmodule, and prints the string value in CModule2.

The reference system treats nil as a special case. When you call Lual_ref for a nil value, it does not create a new reference, but instead returns a constant reference Lua_refnil. When using Lua_rawgeti for Lua_refnil, a nil is pressed into the stack. Here is an example of registering a function, a simple analysis of the following, mainly to understand the code:

Static intRegisterfunc (Lua_state *L) {    //The first parameter is function, check parameterLual_checktype (L,1, lua_tfunction); //duplicate a copy to the top of the stackLua_pushvalue (L,1); Lua_pushvalue (L,1); //Register this function in the registry    intIRef =lual_ref (L, Lua_registryindex); //then use key to index, key is Jellythink_functionLua_setfield (L, Lua_registryindex,"Jellythink_func"); //Press the Iref back into the stack and get the corresponding function in the CModule2 based on the ref reference.Lua_pushinteger (L, IREF); //returns a parameter    return 1;}

The LUA code passes in a function variable, first checking that the parameter is correct (it seems to be a common practice), and then copying two copies (why?). Passing in the variable, in the function is generally to make a copy, do not modify the passed in parameters, of course, the out type argument. )。 Next, look at the comments in the code to get it done. Click here to download the code cmodule.zip.

Environment

Starting with 5.1, all C functions registered in LUA have their own environment table. A function can access its environment by using a pseudo-index like the registry to access the table. The pseudo-index of the environment table is lua_environindex.

This approach to using the environment is similar to using the environment in the LUA module by creating a new table for the module and then sharing the table with all the functions in the module. Only a setfenv function is used in Lua, and in the C module, it is simply setting table to Lua_environindex. Here's a look at the code for an environment.

int Luaopen_environindexdemo (lua_state *l) {    lua_newtable (l);    Lua_replace (L, lua_environindex);     " Cmodule " , Arrayfunc);     return 1 ;}

This registration function takes two more lines of code than the previously written registration function, first creating a new table, and then calling Lua_replace to make the new table the Environment table. When you call Lual_register, all new functions inherit the current environment.

Static intSetValue (Lua_state *L) {    //the values that Lua passes, first check the parametersLual_checkinteger (L,1); Lua_pushvalue (L,1); Lua_setfield (L, Lua_environindex,"Jellythink"); return 0;}//remove the corresponding value from the environmentStatic intGetValue (Lua_state *L) {Lua_getfield (L, Lua_environindex,"Jellythink"); return 1;}

First, set the value to the module environment table. And then remove it from it. This has a lot in common with the above-mentioned registry. Although the environment may be used in place of the registry, if there is no need to share data between different modules, as far as possible do not use the registry, the use of environment-created references, only in this module is visible, so that the use of data to reduce the scope of the application of data, reducing the possibility of error, increased data security. You can click here to download the full code environindexdemo.zip.

"Upvalue"

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 static variables in C language. For those of you who are unfamiliar with upvalue, you can look at the "closures in Lua" article. And this upvalue mechanism allows us to define a variable that is visible only in a particular function. Whenever you create a function in Lua, you can associate any number of Upvalue with this function. Each upvalue can hold a LUA value. Later, when this function is called, the Upvalue can be accessed through a pseudo-index.

This association of C functions with Upvalue is called closure (also known as closures, how familiar names are). A c closure is similar to LUA closure. Closure can use the same function code to create multiple closure, each closure can have a different upvalue. Next, let's take a simple example, on the code:

Static intCOUNT (Lua_state *L) {    intIvalue = Lua_tointeger (L, Lua_upvalueindex (1)); Lua_pushinteger (L,++ivalue); Lua_pushvalue (L,-1); Lua_replace (L, Lua_upvalueindex (1)); return 1;}Static intNewcount (Lua_state *L) {lua_pushcclosure (L,&count,1); return 1;}

The above is part of the important code, in Lua, call Newcount, you can get a closure function count, in Lua, you can use the same as normal variables, the Count function, in Lua each time the Count function is called, It gets the previously saved Upvalue from Upvalue each time and returns it to Lua. Click here to download the full project Upvalue1.

Plus, C module writing (2)

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.