Lua is an embedded language that can be well embedded in other applications. LUA provides us with a flexible set of C APIs that enable C code to interact well with Lua. This includes reading and writing LUA global variables, invoking LUA functions, running LUA code, and registering C functions in turn for LUA calls. Simply put, C can invoke Lua, which in turn can invoke C. Really is the gray often powerful flexible script!! Now, let's learn how to call Lua in C.
In fact, the simplest we've done is to run a LUA script file through a dofile.
A. Stack
LUA interacts with C through a virtual stack, which is strictly LIFO (LIFO) for Lua, and LUA changes the top of the stack when it calls Lua. However, C has greater freedom to retrieve elements from the stack, and even to insert and delete elements at any point.
When Lua starts or LUA calls C, there are at least 20 free slots in the stack, which is sufficient for general invocation. If the parameters of the call are particularly special, you need to check that the slots are not enough, use the following function:
<span style= "White-space:pre" ></span>int lua_checkstack (lua_state* L, int sz);
The API uses an index to refer to the elements in the stack, remembering that the initial index is 1, not 0! That is, the element index in the first push-in stack is 1, and the second pushes the element index in the stack to 2, until the top of the stack. You can also use the index of negative numbers to access the elements at the top of the stack, that is, 1 represents the top element of the stack, and so on.
In the C-language Lua library, there are several functions on the operation of elements in the stack, since there is no generics in the C language implementation, so a function is provided for each data type, where the following data types are temporarily replaced with *.
Checks whether the data type of the index index in the stack is of type int lua_is* (lua_state * l, int index)//returns the type of the data in the index index of the stack int lua_type (lua_state* L, int index)/ /returns the value of the data in the index index of the stack, into the type of * lua_to* (lua_state* l, int index)//INSERT elements of type * into the stack void lua_push* (lua_state* L, type*)
And Since this stuff is a stack, of course, it also provides some of the operations of the stack itself:
Gets the number of elements in the stack int lua_gettop (lua_gettop) (lua_state *l);//set stack top to a specified position void Lua_settop (lua_settop) (lua_state *l, int idx); /pushes the value on the specified index again into the stack void Lua_pushvalue (lua_state *l, int idx);//delete the element with the specified index, and move it down by void Lua_remove (lua_state* L, int idx);// Open a position at index, top move up, and then place the top element of the stack in this position void Lua_insert (lua_state* L, int idx);//pop up the top element of the stack, using this element instead of the index element void Lua_replace (LUA _state* L, int idx);
Take a look at an example where wood has the use of LUA, directly using the C language to manipulate the stack, and view the contents of it:
LuaTest.cpp: Defines the entry point of the console application. #include "stdafx.h" #include <stdio.h> #include <windows.h>//because Lua is a function of C, and our program is C + +, so use extern "C" Introduce header file extern "C" {#include "lua.h" #include "lualib.h" #include "lauxlib.h" #include "luaconf.h"}// Note that you will also need to add the previously compiled Lualib.lib file, which is added by the add-on dependency, properties-----------otherwise you will need to #pragma comment (lib, "Lualib.lib") to add// Print data in stack void Checkstack (lua_state* l) {int top = Lua_gettop (l);//stack size//traverse stack all layers for (int i = 1; I <= top; i++) {i NT type = Lua_type (l, i); switch (type) {case lua_tstring://string printf ("%s\n", lua_tostring (L, i)); Break;case Lua_tboolean ://Boolean printf (Lua_toboolean (L, i)? "true\n": "false\n"), Break;case lua_tnumber://digital printf ("%d\n", Lua_tonumber (L, i)), break;default://other values printf ("%s\n ", Lua_typename (L, i)); break;}} printf ("\ n");} int _tmain (int argc, _tchar* argv[]) {//open lualua_state* L = Lual_newstate ();//Load lib file lual_openlibs (L);//push content into the stack Lua_ Pushboolean (L, 1); Lua_pushstring (L, "hehe"); Lua_pushnumber (l, 100);//Content Checkstack (L) in the print stack,//press the content of index 1 again into the stackLua_pushvalue (L, 1); Checkstack (L);//delete element with index 2 lua_remove (L, 2); Checkstack (L);//Set the top of the stack to 16 (the empty place seems to be one of each type, the rest is empty) lua_settop (L, 16); Checkstack (L);//End Lua_close (l); System ("pause"); return 0;}Results:
True
Hehe
0
True
Hehe
0
True
True
0
True
True
0
True
String
Table
function
UserData
Thread
Proto
(NULL)
(NULL)
(NULL)
(NULL)
(NULL)
(NULL)
(NULL)
Please press any key to continue ...
Two. Simple call to LUA global variable (can be used as a configuration file) since Lua can be loaded by a C + + program, it is also a good use to load the program directly and use it as a configuration file. A simple example:
LUA file:
--configuration file, containing two global variables arg1 = 1ARG2 = 2
C + + programs:
LuaTest.cpp: Defines the entry point of the console application. #include "stdafx.h" #include <stdio.h> #include <windows.h>//because Lua is a function of C, and our program is C + +, so use extern "C" Introduce header file extern "C" {#include "lua.h" #include "lualib.h" #include "lauxlib.h" #include "luaconf.h"}// Note that you will also need to add the previously compiled Lualib.lib file, which is added by the add-on dependency, properties-----------otherwise you will need to #pragma comment (lib, "Lualib.lib") to add// Print data in stack void Checkstack (lua_state* l) {int top = Lua_gettop (l);//stack size//traverse stack all layers for (int i = 1; I <= top; i++) {i NT type = Lua_type (l, i); switch (type) {case lua_tstring://string printf ("%s\n", lua_tostring (L, i)); Break;case Lua_tboolean ://Boolean printf (Lua_toboolean (L, i)? "true\n": "false\n"), Break;case lua_tnumber://digital printf ("%d\n", Lua_tonumber (L, i)), break;default://other values printf ("%s\n ", Lua_typename (L, i)); break;}} printf ("\ n");} Functions that read the Lua script file (here as a configuration file) void Loadlua (lua_state* l, const char* filename, int * arg1, int * arg2) {if (Lual_loadfile (L, F Ilename) | | Lua_pcall (L, 0, 0, 0)) printf ("LoadFile failed! %s\n ", Lua_tostring (L,-1));//If it fails, the top of the stack is an error message//Get global variables, press into the stack Lua_getglobal (L, "arg1"), Lua_getglobal (L, "arg2");//Determine the desired type if (!lua_isnumber (L,-2)) printf (" Arg1 is not number\n "), if (!lua_isnumber (L,-1)) printf (" Arg2 are not number\n ");//parameter values in the extract stack *arg1 = Lua_tointeger (L,-2); *ar G2 = Lua_tointeger (L,-1);} int _tmain (int argc, _tchar* argv[]) {//open lualua_state* L = Lual_newstate ();//Load lib file lual_openlibs (L); int i, j = 0; Loadlua (L, "Test.lua", &i, &j);p rintf ("i =%d, j =%d\n", I, j);//End Lua_close (l); System ("pause"); return 0;}
Result: i = 1, j = 2
Please press any key to continue ...
Simply explain:
Lual_loadfile is a LUA file that is loaded as a program block, but not executed.
Lua_pcall Run the compiled program block.
Lua_getglobal gets the value of the global variable by name and presses it into the stack.
This is through the C program loading LUA files, to the purpose of loading the configuration file, although it looks more troublesome, but the package, it is very useful. and using LUA as a configuration file, on the one hand is easy to operate, do not need to write some of the configuration file read tools, on the other hand, you can add comments in the configuration file and so on, and even write some conditions to judge and so on.
Three. Reading table information table is similar to the structure, can better save some information, when we want to store the configuration file content, and clutter, grouping it is a good choice. LUA supports C reading the information in table. Let's look at an example:
LUA file:
--configuration file, containing two global variables struct = {arg1 = 1, arg2 = 2}
C + + programs:
LuaTest.cpp: Defines the entry point of the console application. #include "stdafx.h" #include <stdio.h> #include <windows.h>//because Lua is a function of C, and our program is C + +, so use extern "C" Introduce header file extern "C" {#include "lua.h" #include "lualib.h" #include "lauxlib.h" #include "luaconf.h"}// Note that you will also need to add the previously compiled Lualib.lib file, which is added by the add-on dependency, properties-----------otherwise you will need to #pragma comment (lib, "Lualib.lib") to add// Print the size of the stack void Checkstack (lua_state* l) {int top = Lua_gettop (l);//stack size printf ("The size of the stack is%d\n", top);} Read a table of data, table more structured void Loadlua (lua_state* L, const char* filename, int * arg1, int * arg2) {///and direct read, load file First, then execute I F (Lual_loadfile (l, filename) | | lua_pcall (l, 0, 0, 0)) printf ("LoadFile failed! %s\n ", lua_tostring (L,-1));//If it fails, the top of the stack is an error message checkstack (l);//The Stack is empty//the struct structure is placed in the stack Lua_getglobal (l," struct "); if ( ! Lua_istable (L,-1)) printf ("Struct is not table!\n"); Checkstack (L);//The stack size is 1//extracted from the struct arg1 placed on top of the stack Lua_getfield (l,-1, "arg1"), if (! Lua_isnumber (L,-1)) printf ("Arg1 is not Number!\n "); Checkstack (L);//At this time the stack size is 2*arg1 = Lua_toiNteger (L,-1);//The top element of the stack pops up Lua_pop (L, 1) when the previous element is exhausted; Checkstack (L);//At this time the stack size is 1//extract arg2 placed on top of the stack Lua_getfield (l,-1, "arg2"), if (! Lua_isnumber (L,-1)) printf ("Arg2 is not number!\n "); Checkstack (l); *arg2 = Lua_tointeger (L,-1);} int _tmain (int argc, _tchar* argv[]) {//open lualua_state* L = Lual_newstate ();//Load lib file lual_openlibs (L); int i, j = 0; Loadlua (L, "Test.lua", &i, &j);p rintf ("i =%d, j =%d\n", I, j);//End Lua_close (l); System ("pause"); return 0;}Result: the size of the stack is 0
The size of the stack is 1
The size of the stack is 2
The size of the stack is 1
The size of the stack is 2
i = 1, j = 2
Please press any key to continue ...
Or the last two data, but this time they were placed in a table, even if there are the same n groups, you can use n table to store, do not worry about the messy problem.
Simply analyze the process of C reading table:
is still loaded via loadfile, and then still getglobal gets the global variable, but this time the global variable is a table, check if it is really a table before doing the next step, and then, through another function getfiled () Get the contents of a specific field in the table and place it on top of the stack. After reading one, it pops up, then gets the contents of the next field again, reads, and so on.
Bright This table-type configuration file is almost the same as XML. Have not found a good XML parser under C + +, it is not possible to use LUA later.
Four. Calling the LUA function
Finally to this step, the previous only can be called the configuration file, this step is really called a script!! In fact, the use of C to invoke the Lua script is relatively simple, or use that stack for parameter delivery.
See a simple example:
LUA file:
--add fucntionfunction Add (A, b) return a + bend
C + + programs:
LuaTest.cpp: Defines the entry point of the console application. #include "stdafx.h" #include <stdio.h> #include <windows.h>//because Lua is a function of C, and our program is C + +, so use extern "C" Introduce header file extern "C" {#include "lua.h" #include "lualib.h" #include "lauxlib.h" #include "luaconf.h"}// Note that you will also need to add the previously compiled Lualib.lib file, which is added by the add-on dependency, properties-----------otherwise you will need to #pragma comment (lib, "Lualib.lib") to add// Print data in stack void Checkstack (lua_state* l) {int top = Lua_gettop (l);//stack size//traverse stack all layers for (int i = 1; I <= top; i++) {i NT type = Lua_type (l, i); switch (type) {case lua_tstring://string printf ("%s", lua_tostring (L, i)); Break;case lua_tboolean:/ /boolean printf (Lua_toboolean (L, i)? "True": "false"); break;case lua_tnumber://number printf ("%g", Lua_tonumber (L, i)), break;default://other value printf ("%s", Lua_ TypeName (L, I)); break;}} printf ("\ n");p rintf ("The size of the stack is%d\n", top);} Read a table of data, table more structured void Loadlua (lua_state* L, const char* filename, int * arg1, int * arg2) {///and direct read, load file First, then execute I F (Lual_loadfile (l, filename) | | lua_pcall (l, 0, 0, 0) printF ("LoadFile failed! %s\n ", lua_tostring (L,-1));//If it fails, the top of the stack is an error message checkstack (l);//The Stack is empty//the struct structure is placed in the stack Lua_getglobal (l," struct "); if ( ! Lua_istable (L,-1)) printf ("Struct is not table!\n"); Checkstack (L);//The stack size is 1//extracted from the struct arg1 placed on top of the stack Lua_getfield (l,-1, "arg1"), if (! Lua_isnumber (L,-1)) printf ("Arg1 is not Number!\n "); Checkstack (L);//At this time the stack size is 2*arg1 = Lua_tointeger (L,-1);//The last element is used up, the top element of the stack pops up Lua_pop (l, 1); Checkstack (L);//At this time the stack size is 1//extract arg2 placed on top of the stack Lua_getfield (l,-1, "arg2"), if (! Lua_isnumber (L,-1)) printf ("Arg2 is not number!\n "); Checkstack (l); *arg2 = Lua_tointeger (L,-1);} Call Lua's function double Add (lua_state* L, double x, double y) {//press into functions and parameters//extract functions from Lua, put into the stack Lua_getglobal (L, "add");// Two parameters are pressed into the stack lua_pushnumber (l, x); Lua_pushnumber (l, y); Checkstack (L);//Make Call if (Lua_pcall (L, 2, 1, 0)! = 0) printf ("function called failed! %s\n ", Lua_tostring (L,-1)); Checkstack (L);//Extract the result from the stack if (!lua_isnumber (L,-1)) printf ("Function must return a double number!\n");d ouble result = Lua_ Tonumber (L,-1); Lua_pop (L, 1); Checkstack (L); return result;} Read Lua file and execute function void Getluafunctiorn (lua_state* l, const char* filename) {if (Lual_loadfile (l, filename) | | lua_pcall (l, 0, 0, 0)) printf ("Load file failed! %s\n ", lua_tostring (L,-1));d ouble Resulet = Add (L, 1.5, 2.5);p rintf (" result is%f\n ", Resulet);} int _tmain (int argc, _tchar* argv[]) {//open lualua_state* L = Lual_newstate ();//Load lib file lual_openlibs (L);// Use function Getluafunctiorn (L, "Test.lua");//End Lua_close (l); System ("pause"); return 0;}
Result: Boolean 1.5 2.5
The size of the stack is 3
4
The size of the stack is 1
The size of the stack is 0
Result is 4.000000
Please press any key to continue ...
When we call the LUA function, we first need to know the name of the function in Lua and the number of arguments. These need to be placed in the stack before the call. The function needs to be extracted from the name by the Getglobal function and put the function on the stack. The parameters are then pressed into the stack in turn. After the preparation is done, the LUA function is called through the Lua_pcall function. The Lua_pcall function has 4 parameters, the first parameter is lua_state, the second argument is the number of arguments passed to the function, the third parameter is the number of results expected to return, and the last parameter is the index of the function that is being handled incorrectly. As with the previous assignment, if our actual value is more than the value given by Lua_pcall, it will be shed, if less, use nil.If the function has more than one return parameter, the first argument is pressed into the stack, then the second one, and so on. At this point, such as returning three results, the index of the first result is-3, the second is-2, and the last one is-1.If the LUA function runs in an error, Lua_pcall returns a nonzero value and presses an error message into the stack. However, if there is an error handler before pressing the error message, the error handler is executed first. The last parameter of Lua_pcall can specify the location of the error handler, if 0 indicates that the wood has an error handling function. If so, this parameter represents the index of the error handler in the stack, so if there is an error handler, it needs to be pressed into the stack first.Error-handling functions are also not an error-handling function, and error handlers are not invoked when a memory allocation error occurs or when an error handler fails.
Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.
LUA Learning Note--c calling Lua