Preface
Anyone who has written Windows programs knows that for applications, if they need to save some configuration information locally, we often write these configuration information in the registry or local configuration files. Many applications write some configuration information in the configuration file, such as files ending in ini. There are many configuration files and are widely used. Then, when the application starts, it will parse this configuration file and read some configuration information.
One of the important uses of Lua is as a configuration language. This article will combine Lua to expand applications, which provides greater flexibility and convenience.
This blog mainly summarizes the use of C++ and Lua for interaction, involving obtaining the values of ordinary variables in Lua, the values of tables in Lua, and calling functions in Lua. Let's start now.
Start with the simplest example
A GUI program reads the size of the window from the configuration file, thereby setting the size of the window. Next, I will write a form program based on MFC to complete this function. Click here to download and complete the code project. I'll post the key code:
bool CLuaConfig::LoadConfig()
{
L = luaL_newstate();
if (!L)
{
return false;
}
// Load the configuration file
int bRet = luaL_loadfile(L, pConfigFile);
if (bRet)
{
return false;
}
// Run the configuration file
bRet = lua_pcall(L, 0, 0, 0);
if (bRet)
{
return false;
}
// Read high
lua_getglobal(L, "width");
lua_getglobal(L, "height");
// width
if (!lua_isnumber(L, -2))
{
return false;
}
// height
if (!lua_isnumber(L, -1))
{
return false;
}
iWindowHeight = lua_tointeger(L, -1);
iWindowWidth = lua_tointeger(L, -2);
return true;
}
I won’t talk about luaL_newstate, it’s useless; luaL_loadfile is used to load a lua file and then call lua_pcall to run the compiled program block. lua_pcall runs Lua code in protected mode. That is to say, if an error occurs, lua_pcall will return an error code and will not directly crash. After running the program block, the lua_getglobal function is called twice, and this function will push the global variable value into the stack. Therefore, the width value is at the index of -2 and the height value is at the index of -1; next, there is no need to say more. That's it. Download the program, run it, it will be OK. Modify the files in the code folder and see the running results.source codeDownload here.
Table operation
In Lua, for things like table bugs, if the C API cannot operate tables, can we still have fun? Let's take a look at how the C API operates on tables. Now there are the following Lua statements:
background = {r = 0.3, g = 1, b = 0.5}
So, how does the C API read this code and parse every field in it. I first pasted the code and then analyzed it one by one:
// Read global data into the stack
lua_getglobal(L, "background");
if (!lua_istable(L, -1))
{
// If it is not a table, the error message will be displayed
cout << "It's not a table." << endl;
return 0;
}
// Read the value of the field in the table and push the value into the stack
lua_getfield(L, -1, "r");
// Read the value in the stack
if (!lua_isnumber(L, -1))
{
// If it is not a real number, an error message will be displayed
cout << "It's not a number." << endl;
return 0;
}
double fValue = lua_tonumber(L, -1);
cout << "r => " << fValue << endl;
Forgive me for omitting code like luaL_newstate. OK, it makes sense to read a table and read a global variable. It is divided into the following steps:
1. Use lua_getglobal to read this variable and read the table into the stack;
2. Use lua_getfield to read the value of the field in the table and read the value of the field into the stack;
3. Use the lua_to* series function to read the value of the field from the stack.
This is the operation of reading table, so what about setting table? We can write our own values to the stack, how should we do this? Look at the code:
// Set the value you want to set to the stack
lua_pushnumber(L, 0.55);
// Set this value to the table
lua_setfield(L, -2, "r");
It is the above two lines of code. Of course, you also need to use lua_getglobal to read the table variable first, read the table into the stack, and then set it according to the above two lines of code. What is the specific meaning of the above two lines of code?
1. The lua_push* series function is to put a new value that needs to be set into the stack;
2. The lua_setfield function is a function of nature, but here is the set semantics, and set lua_push* to the value in the stack to the corresponding key of the table.
Now that you read the table and set the table, it says, how to completely create a new table in the table? We have this need. what to do?
// Create a new table and push it into the stack
lua_newtable(L);
// Set values in table
lua_pushstring(L, "https://"); // Push the value into the stack first
lua_setfield(L, -2, "website"); // Set the value to the table
// Set another value
lua_pushstring(L, "Jelly Think | an original article sharing website");
lua_setfield(L, -2, "description");
I posted a few important lines of code on it. The most important thing is a lua_newtable function. This function will create a new table and place this table on the stack. The next step is the same as the value of the table set above. source codeDownload one、Download 2。
Calling Lua function
Yes, you read that right, you can define a function in a lua file and then call this function in C++, which seems to be "high-end". Now let me talk about this "high-end" function; habitually upload the code:
// Let's take a look at the function calls that have parameters and return worthy of function calls
// Now, an add function is defined in the calculation of the sum of two values, and these two values are passed in with parameters.
// After obtaining the sum, the sum will be returned. Now we call the add function in C++.
lua_getglobal(L, "add"); // Get the function and push it into the stack
lua_pushnumber(L, 10); // Press the first parameter
lua_pushnumber(L, 20); // Press in the second parameter
// Complete the call
iRet = lua_pcall(L, 2, 1, 0);
if (iRet)
{
const char *pErrorMsg = lua_tostring(L, -1);
cout << pErrorMsg << endl;
lua_close(L);
return 0;
}
// Obtain calculation results
iRet = lua_isnumber(L, -1);
if (!iRet)
{
cout << "Error occured." << endl;
lua_close(L);
return 0;
}
double fValue = lua_tonumber(L, -1);
cout << "Result is " << fValue << endl;
The above code calls the following lua function:
-- There are parameters, there are return values
function add(iA, iB)
return iA + iB
end
This simple Lua function has nothing to say, let’s talk about the long C++ code above. In Lua, functions and ordinary values are the same, so C++ calls functions in Lua, which are divided into the following steps:
Use lua_getglobal to get the function and then push it onto the stack;
If this function has parameters, you need to push the parameters of the function into the stack in turn;
After all these preparations are ready, lua_pcall will be called to start calling the function. After the call is completed, the return value will be pushed into the stack;
The final return process is worth it, and the call is completed.
Source code heredownload。
Summarize
After summarizing this article, I spent a total of 4 days of spare time, and the time was mainly spent on the writing of demos. Okay, I hope this article will be helpful to everyone. If you think it's pretty good, you can share this article with more friends. Of course, you can also scan the QR code on the right side of the page to help me write better articles, which must be excellent.