one, Lua Stacks
To understand Lua and C + + interactions, first understand the LUA STACK.
To put it simply, the main method of communication between Lua and C + + languages is a ubiquitous virtual stack. The stack is characterized by advanced Post-out.
In lua, the LUA stack is a struct, and the stack index is either positive or negative, the difference being that positive index 1 always represents the bottom of the stack, and negative index 1 always represents the top of the Stack.
The LUA stack is similar to the following definition, which was created when the lua_state was created:
TValue stack[max_stack_len]//the stack_init function of lstate.c can be found in the knowledge
The data types of the stack include numeric values, strings, pointers, talbe, closures, etc., And here is an example of a stack:
Executing the following code allows you to render the picture on your LUA stack.
Lua_pushcclosure (L, func, 0)//create and press into a closure
Lua_createtable (L, 0, 0)//new and press into a table
Lua_pushnumber (L, 343)//press into a number
Lua_pushstring (L, "mystr")//press into a string
Here to illustrate, you press into the type has values, strings, tables and closures [in C appears to be different types of values], but the final is unified with TValue this data structure to save:), the following is a simple illustration of this data structure:
The TValue structure corresponds to all data types in lua, is a {value, type} structure, which is the implementation of a dynamic type in lua, which binds values and types together , uses TT to record the type of value, and value is a union structure, defined by value, You can see that this Union has four domains, which first explains the simple
P--a pointer can be stored, which is actually the light userdata structure in LUA
N--all values exist here, but int, or float
B--the Boolean value exists here, Note that Lua_pushinteger is not present here, but exists in n, and B is stored in Boolean
Gc--other types such as table, thread, closure, and string require memory management garbage collection exist here
A GC is a pointer to a type defined by the Union gcobject, as can be seen, with string, userdata, closure, table, proto, upvalue, Thread
The following figure can be drawn from the following conclusions:
1. lua, number, boolean, nil, light UserData Four types of values are directly present on the stack element, regardless of garbage collection.
2. lua, string, table, closure, userdata, thread exist only pointers in the elements of the stack, and they will be garbage collected after the end of the life Cycle.
second, the operation of the stack
Because Lua communicates with C + + through the stack, LUA provides the C API to manipulate the STACK.
Let's look at one of the simplest examples:
#include <iostream> #include <string.h> using namespace std; extern "C" { #include "lua.h" #include "lauxlib.h" #include "lualib.h" } void main () { //1. Create a state lua_state *l = lual_newstate (); 2. Into the stack operation lua_pushstring (L, "I am so cool~"); Lua_pushnumber (l,20); 3. Value Operation if (lua_isstring (l,1)) { //determine if it can be converted to string cout<<lua_tostring (l,1) <<endl; Convert to string and return } if (lua_isnumber (l,2)) { cout<<lua_tonumber (l,2) <<endl; } 4. Close State lua_close (L); return; }
It can be simply understood that Lual_newstate returns a pointer to the stack, and other comments should be understood.
Some other stack operations:
int lua_gettop (lua_state *l); Returns the top index of the stack (that is, the stack length) void lua_settop (lua_state *l, int idx); void lua_pushvalue (lua_state *l, int idx);//pushes A copy of the value on the IDX index into the top void lua_remove (lua_state *l, int idx); Remove the value on the IDX index void lua_insert (lua_state *l, int idx); Pop up the top of the stack element and insert the index idx position void lua_replace (lua_state *l, int idx); POPs the top element of the stack and replaces the value of the index IDX position
Ua_settop sets the top of the stack to a specified position, which is to modify the number of elements in the STACK. If the value is higher than the original stack, then the high part nil complements, If the value is lower than the original stack, then the portion of the original stack is Discarded. So you can use Lua_settop (0) to empty the stack .
third, C + + calls Lua
We can often use LUA files as configuration Files. File configuration information such as Ini,xml. Now let's use C + + to read the variables in the LUA file, table, Function.
Lua and C communication have such a convention: all LUA values are managed by lua, the values produced in C + + do not know, similar to the meaning of the expression: " if you (c + +) want what, You tell me (lua), I come to produce, and then put on the stack, You can only manipulate this value through the api, I am just in my world ", this is important because:
"if you want something, you tell me, i'll make it." it is guaranteed that LUA is responsible for the life cycle and garbage collection of variables in lua, so the values must be created by LUA (the bookkeeping information used for life cycle management is added at the time of Creation )
"then put on the stack, you can only manipulate the value through the api," the LUA API gives C a complete set of operating interfaces, which is equivalent to the agreed communication protocol , if LUA customers use this interface, then LUA itself will not have any "unexpected" Error.
The phrase "i am my world" embodies Lua and C + + as a demarcation of two different systems, the value in C/S + +, which Lua does not know, and Lua is only responsible for its WORLD.
There is now such a Hello.lua file:
str = "I am so cool" tbl = {name = "shun", id = 20114442} function add (b) return a + B end
We write a test.cpp to read it:
#include <iostream> #include <string.h> using namespace std; extern "C" {#include "lua.h" #include "lauxlib.h" #include "lualib.h"} void main () {//1. create LUA State Lua_state *l = lual_newstate (); if (L = = NULL) {return; }//2. load Lua file int bRet = Lual_loadfile (L, "hello.lua"); If (bRet) {cout<< "load file error" <<endl; return; }//3. Run Lua file BRet = Lua_pcall (l,0,0,0); If (bRet) {cout<< "pcall error" <<endl; return; }//4. Read variable Lua_getglobal (L, "str"); String str = lua_tostring (l,-1); cout<< "str =" <<str.c_str () <<endl; str = I am so cool~//5. read table Lua_getglobal (L, "tbl"); Lua_getfield (l,-1, "name"); str = lua_tostring (l,-1); cout<< "tbl:name =" <<str.c_str () <<endl; Tbl:name = shun//6. Read function Lua_getglobaL (l, "add"); Get the function, press into the stack lua_pushnumber (L, 10); Press in the first parameter Lua_pushnumber (L, 20); Press the second parameter int iret= lua_pcall (L, 2, 1, 0);//call function, After the call is completed, the return value will be pressed into the stack, 2 indicates the number of arguments, and 1 indicates the number of results Returned. If (iRet)//call error {const char *perrormsg = lua_tostring (L,-1); cout << perrormsg << endl; Lua_close (L); return; } if (lua_isnumber (l,-1))//value output {double fvalue = Lua_tonumber (l,-1); cout << "Result is" << fvalue << endl; }//to This point, the scenario in the stack is://=================== stack top ===================//index type VALUE//4 int:3 0//3 STRING:SHUN//2 TABLE:TBL//1 string:i am so cool~//============== ===== Bottom ===================//7. Close State lua_close (L); return; }
Knowing how to read it, let's look at how to modify the value of table in the Code above:
Set the value you want to set to the stack lua_pushstring (l, "i'm a hot pot ~"); Set this value to table (at which time the TBL position on the stack is 2) lua_setfield (L, 2, "name");
We can also create a new table:
Create a new table and press it into the stack lua_newtable (L); Set the value in table lua_pushstring (l, "Give me a girl friend!"); press the value into the stack Lua_setfield (l,-2, "str");//set the value to table and G ive me a girl friend out of the stack
It is important to note that the stack operation is based on top of the stack, that is, it only goes to the value of the top of the Stack.
To give a simpler example, the function call process is to first put the function into the stack, the parameters into the stack, and then call the function with lua_pcall, when the stack top is a parameter, the stack is a function, so the stack process will be roughly: parameter out of the stack, save parameters, such as parameter, save parameter Function---call Function---returns The result into the STACK.
Similar to the lua_setfield, set the value of a table, you must first put the value out of the stack, save, and then find the table Position.
If you don't understand it, see the following example:
Lua_getglobal (L, "add"); Gets the function, presses into the stack lua_pushnumber (L, ten); Press in the first parameter lua_pushnumber (L, x); Press into the second parameter int iret= lua_pcall (l, 2, 1, 0);//2 arguments out of the stack, function out of the stack, press the function to return the result lua_pushstring (l, "i am a handsome pot ~"); Lua_setfield (L, 2, "name"); Will be "i am a handsome pot ~" out of the stack
In addition, please add:
Lua_getglobal (L, "var") performs two steps: 1. put Var in the stack, 2. The value of Var is found by Lua and the value of VAR is returned to the top of the stack (replacing var).
The function of Lua_getfield (l,-1, "name") is equivalent to lua_pushstring (L, "name") + lua_gettable (l,-2)
The correspondence between LUA value and C value
|
C |
Lua |
Nil |
No |
{value=0, TT = t_nil} |
Boolean |
int not 0, 0 |
{value= non-0/0, tt = t_boolean} |
Number |
Int/float et 1.5 |
{value=1.5, TT = t_number} |
Lightuserdata |
void*, int*, Various * point |
{value=point, TT = t_lightuserdata} |
String |
Char str[] |
{value=gco, tt = t_string} gco=tstring obj |
Table |
No |
{value=gco, tt = t_table} gco=table obj |
UserData |
No |
{value=gco, tt = t_udata} Gco=udata obj |
Closure |
No |
{value=gco, tt = t_function} gco=closure obj |
As you can see, some of the types provided in Lua are corresponding to those in c, and also some types that are not available in C. Some of these medications are particularly illustrative:
Nil value, There is no correspondence in c, but a nil value can be pressed into Lua via Lua_pushnil
Note: the lua_push* family functions have the semantics of "create a type of value and press in" because all of the variables in Lua are created and saved in lua, and for those LUA types that have a corresponding relationship with c, LUA passes an additional parameter from the api, The LUA variable that creates the corresponding type is placed on top of the stack, and LUA creates the corresponding variable at the top of the stack for no LUA type of the corresponding type in C.
For example: lua_pushstring (L, "string") Lua creates a tstring obj based on "string", bound to the newly allocated top element of the stack
Lua_pushcclosure (l,func, 0) Lua creates a Closure obj based on func, bound to the newly allocated top element of the stack
Lua_pushnumber (l,5) LUA modifies the top element of the newly allocated stack directly, assigning 5 to the corresponding domain
Lua_createtable (l,0, 0) Lua creates a Tabke obj, bound to the newly allocated top element of the stack
In summary, this is the flow of C value–> Lua value, whether you want to put a simple 5 into the world of lua, or create a table that will cause
1. Stack top New allocation element 2. Bind or assign a value
Or to repeat a sentence, a C value into the stack is into the world of lua, LUA will generate a corresponding structure and management, and henceforth no longer rely on this C value
Lua value–> C value, is implemented through the lua_to* family api, it is simple to remove the corresponding C field value is ok, only those who have the corresponding value in C LUA value, such as table can not to C value, so API Bud No Provides an interface such as Lua_totable.
Iv. Lua calls C + +
We implement it in three Ways.
Method One: write the module directly into the LUA source code
In lua, we can write a function in LUA.C and then recompile the LUA File.
After compiling it, it's like This: ()
Then we can add our own functions to the LUA.C. The function to follow the specification (which can be viewed in Lua.h) is as Follows:
typedef int (*lua_cfunction) (lua_state *l);
In other words, all functions must receive a lua_state as an argument and return an integer Value. Because this function uses the LUA stack as a parameter, it can read any number and any type of arguments from the Stack. The return value of this function indicates how much of the return value is pressed into the LUA stack when the function returns. (because LUA functions are capable of returning multiple values)
We then add the following function to the Lua.c:
This is my function static int gettwovar (lua_state *l) { //pushes 2 values into the function stack lua_pushnumber (L, x); Lua_pushstring (L, "hello"); return 2; } In the Pmain function, add the following code after the Lual_openlibs function://register function lua_pushcfunction (l, gettwovar);//put functions in the stack lua_setglobal (l, " Gettwovar "); Set LUA global Variables Gettwovar
By finding Lua.h
/#define lua_register (l,n,f) (lua_pushcfunction (l, (f)), lua_setglobal (l, (n)))
We found that the previous registration function can be written like this:
Lua_register (L, "gettwovar", gettwovar);
run, Results
of course, in general, we do not recommend to modify other People's code, more inclined to write their own independent C + + module for the LUA call, the following is how to Implement.
Method Two: use a static dependency method
1. Create a new empty Win32 console project, remember that in the VC + + directory, the header files in Lua and the directory of LIB files are included, and then the Linker-and additional dependencies, including Lua51.lib and lua5.1.lib.
2. Create a new Avg.lua under the directory as Follows:
avg, sum = average ("the average is", avg) print ( "the sum is", sum)
3. The new test.cpp is as Follows:
#include <stdio.h> extern "C" { #include "lua.h" #include "lualib.h" #include "lauxlib.h" }/ * Pointer to the LUA interpreter */ lua_state* L; static int average (lua_state *l) {/ * Gets the number of arguments */ int n = lua_gettop (L); Double sum = 0; int i; /* Loop to find the sum of the parameters */ for (i = 1; i <= n; i++) {/ * Sum */ sum + = Lua_tonumber (L, i); } /* press-in Average * /lua_pushnumber (L, sum/n); /* Press in and * /lua_pushnumber (L, sum); /* returns the number of return values */return 2; } int main (int argc, char *argv[]) { /* Initialize LUA * /L = Lua_open (); /* load into LUA basic library * /lual_openlibs (L); /* Registration function * /lua_register (L, "average", average); /* Run the script * /lual_dofile (L, "avg.lua"); /* Clear Lua * /lua_close (L); /* Pause * /printf ("press Enter to exit ..."); GetChar (); return 0; }
To execute, we can get the Result:
The approximate order is that we write a module function in C + +, Register the function in the LUA interpreter, then execute our LUA file by C + + and invoke the function that we just registered in Lua.
It looks awkward, and There's wood. The next step is to describe how the DLL is Called.
Method three: How to use DLL dynamic link
Let's start with a new DLL project named Mlualib. (so The last DLL exported is also MLualib.dll)
Then write our C + + module, take the function as an example, we will first create a new. H file and A. CPP File.
H file is as Follows: (if you are not quite able to understand the contents of the header file, click Here: http://blog.csdn.net/shun_fzll/article/details/39078971. )
#pragma once extern "C" { #include "lua.h" #include "lualib.h" #include "lauxlib.h" } #ifdef Lua_exports #define LUA_API __declspec (dllexport) #else #define LUA_API __declspec (dllimport) # endif extern "C" lua_api int luaopen_mlualib (lua_state *l);//define export function
The. CPP files are as Follows:
#include <stdio.h> #include "mLualib.h" static int averagefunc (lua_state *l) { int n = Lua_ GetTop (L); Double sum = 0; int i; /* Loop to find the sum of the parameters */ for (i = 1; i <= n; i++) sums + = Lua_tonumber (L, i); Lua_pushnumber (L, sum/n); Press average lua_pushnumber (L, sum); Press in and return 2; Returns two results } static int sayhellofunc (lua_state* L) { printf ("hello world!"); return 0; } static const struct Lual_reg mylib[] = { {"average", averagefunc}, {"sayHello", sayhellofunc}, { null, null} //the Last pair in the array must be {null, null}, to denote the end }; int luaopen_mlualib (lua_state *l) { lual_register (L, "ss", mylib); return 1; The Mylib table is pressed into the stack, so you need to return 1 }
Don't understand it's okay, let's compile it and then create a new Lua file that we'll call in Lua: (remember to copy the DLL file to the Lua file directory before Calling)
Require "mlualib" local ave,sum = Ss.average (1,2,3,4,5)//parameter corresponds to data in the stack print (ave,sum) --3 Ss.sayhello () --hello world!
Successful call to have wood there? We see the output Information.
What's Going on here? Comb:
1. We have written averagefunc averaging and Sayhellofunc functions,
2. Then wrap the function inside the Mylib array, the type must be Lual_reg
3. The two functions are exported by the Luaopen_mlualib function and registered in LUA.
So why write like this? In fact, when we're in Lua:
Require "mlualib"
When it's written like this, Lua will do this:
Local Path = "mLualib.dll" local f = package.loadlib (path, "luaopen_mlualib") --return luaopen_mlualib function f () --execution
So when we write a module like this, when writing the luaopen_xxx export function, xxx is best to be the same as the project name (because the project name and dll).
It is important to note that the lua_state in the function arguments are private and each function has its own stack. The stack is automatically emptied when a c/c + + function presses the return value into the LUA STACK.
V. Summary
Lua and C + + interact through a virtual stack.
C + + Call Lua is actually: C + + first put the data in the stack, the LUA to the stack to fetch the data, and then return the data corresponding to the top of the stack, and then back to C + + from the top of the Stack.
LUA calls the same thing: write your own C module, then register the function in the LUA interpreter, and then call the Module's function by Lua.
This article does not involve LUA grammar learning, if necessary, please visit: http://book.luaer.cn/
Lua and C + +