程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> Lua和C++交互詳細總結_3_C++調用Lua

Lua和C++交互詳細總結_3_C++調用Lua

編輯:關於C++

三C++調用Lua

我們經常可以使用Lua文件來作配置文件。類似ini,xml等文件配置信息。現在我們來使用C++來讀取Lua文件中的變量,table,函數。

lua和c通信時有這樣的約定: 所有的lua中的值由lua來管理, c++中產生的值lua不知道, 類似表達了這樣一種意思: "如果你(c/c++)想要什麼, 你告訴我(lua), 我來產生, 然後放到棧上, 你只能通過api來操作這個值, 我只管我的世界", 這個很重要, 因為:

"如果你想要什麼, 你告訴我, 我來產生"就可以保證, 凡是lua中的變量, lua要負責這些變量的生命周期和垃圾回收, 所以, 必須由lua來創建這些值(在創建時就加入了生命周期管理要用到的簿記信息)

"然後放到棧上, 你只能通過api來操作這個值", lua api給c提供了一套完備的操作界面, 這個就相當於約定的通信協議, 如果lua客戶使用這個操作界面, 那麼lua本身不會出現任何"意料之外"的錯誤.

"我只管我的世界"這句話體現了lua和c/c++作為兩個不同系統的分界, c/c++中的值, lua是不知道的, lua只負責它的世界

現在有這樣一個hello.lua 文件:

str = "I am so cool"  
tbl = {name = "shun", id = 20114442}  
function add(a,b)  
    return a + b  
end
我們寫一個test.cpp來讀取它:
#include   
#nclude   
using namespace std;  
   
extern "C"  
{  
    #include "lua.h"  
    #include "lauxlib.h"  
    #include "lualib.h"  
}  
void main()  
{  
    //1.創建Lua狀態  
    lua_State *L = luaL_newstate();  
    if (L == NULL)  
    {  
        return ;  
    }  
   
    //2.加載Lua文件  
    int bRet = luaL_loadfile(L,"hello.lua");  
    if(bRet)  
    {  
        cout<<"load file error"<知道怎麼讀取後,我們來看下如何修改上面代碼中table的值:
// 將需要設置的值設置到棧中  
lua_pushstring(L, "我是一個好人~");  
// 將這個值設置到table中(此時tbl在棧的位置為2)  
lua_setfield(L, 2, "name");
我們還可以新建一個table:
// 創建一個新的table,並壓入棧  
lua_newtable(L);  
// 往table中設置值  
lua_pushstring(L, "Give me a girl friend !"); //將值壓入棧  
lua_setfield(L, -2, "str"); //將值設置到table中,並將Give me a girl friend 出棧

需要注意的是:堆棧操作是基於棧頂的,就是說它只會去操作棧頂的值。

舉個比較簡單的例子,函數調用流程是先將函數入棧,參數入棧,然後用lua_pcall調用函數,此時棧頂為參數,棧底為函數,所以棧過程大致會是:參數出棧->保存參數->參數出棧->保存參數->函數出棧->調用函數->返回結果入棧。

類似的還有lua_setfield,設置一個表的值,肯定要先將值出棧,保存,再去找表的位置。

再不理解可看如下例子:

lua_getglobal(L, "add");        // 獲取函數,壓入棧中  
lua_pushnumber(L, 10);          // 壓入第一個參數  
lua_pushnumber(L, 20);          // 壓入第二個參數  
int iRet= lua_pcall(L, 2, 1, 0);// 將2個參數出棧,函數出棧,壓入函數返回結果  
lua_pushstring(L, "我是一個好人~");  //   
lua_setfield(L, 2, "name");             // 會將"我是一個大帥鍋~"出棧

另外補充一下:

lua_getglobal(L,"var")會執行兩步操作:1.將var放入棧中,2.由Lua去尋找變量var的值,並將變量var的值返回棧頂(替換var)。

lua_getfield(L,-1,"name")的作用等價於 lua_pushstring(L,"name") + lua_gettable(L,-2)

lua value 和 c value的對應關系:

  c lua nil 無 {value=0, tt = t_nil} boolean int 非0, 0 {value=非0/0, tt = t_boolean} number int/float等 1.5 {value=1.5, tt = t_number} lightuserdata void*, int*, 各種* point {value=point, tt = t_lightuserdata} string char str[] {value=gco, tt = t_string} gco=TString obj table 無 {value=gco, tt = t_table} gco=Table obj userdata 無 {value=gco, tt = t_udata} gco=Udata obj closure 無 {value=gco, tt = t_function} gco=Closure obj

可以看出來, lua中提供的一些類型和c中是對應的, 也提供一些c中沒有的類型. 其中有一些藥特別的說明一下:

nil值, c中沒有對應, 但是可以通過lua_pushnil向lua中壓入一個nil值

注意:lua_push*族函數都有"創建一個類型的值並壓入"的語義, 因為lua中所有的變量都是lua中創建並保存的, 對於那些和c中有對應關系的lua類型, lua會通過api傳來的附加參數, 創建出對應類型的lua變量放在棧頂, 對於c中沒有對應類型的lua類型, lua直接創建出對應變量放在棧頂.

例如: lua_pushstring(L, “string”) lua根據"string"創建一個 TString obj, 綁定到新分配的棧頂元素上

lua_pushcclosure(L,func, 0) lua根據func創建一個 Closure obj, 綁定到新分配的棧頂元素上

lua_pushnumber(L,5) lua直接修改新分配的棧頂元素, 將5賦值到對應的域

lua_createtable(L,0, 0)lua創建一個Tabke obj, 綁定到新分配的棧頂元素上

總之, 這是一個c value –> lua value的流向, 不管是想把一個簡單的5放入lua的世界, 還是創建一個table, 都會導致

1. 棧頂新分配元素 2. 綁定或賦值

還是為了重復一句話, 一個c value入棧就是進入了lua的世界, lua會生成一個對應的結構並管理起來, 從此就不再依賴這個c value

lua value –> c value時, 是通過 lua_to* 族api實現, 很簡單, 取出對應的c中的域的值就行了, 只能轉化那些c中有對應值的lua value, 比如table就不能to c value, 所以api中夜沒有提供 lua_totable這樣的接口.

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved