Lua和C++的交互——進一步詳解

 上篇文章已經寫到過整體環境的配置和給了份完整的代碼,下面這篇文章是來對每個語句進行一個簡單的剖析:

在ladd函數中執行了lua中的add函數,首先看lua_getglobal函數:

void lua_getglobal (lua_State *L, const char *name);

把全局變量 name 裏的值壓入堆棧。這個是用一個宏定義出來的:

#define lua_getglobal(L,s)  lua_getfield(L, LUA_GLOBALSINDEX, s)

這裏lua_getglobal(L, “add”)把add函數壓入堆棧,接着把x和y參數壓入堆棧,然後調用lua_call執行add函數,關於lua_call函數:

void lua_call (lua_State *L, int nargs, int nresults);

它的功能是調用一個函數,需要遵循以下協議:

      首先,要調用的函數應該被壓入堆棧;

      接着把需要傳遞給這個函數的參數按正序壓棧; 這是指第一個參數首先壓棧。 

      最後調用一下lua_call; nargs 是你壓入堆棧的參數個數。 當函數調用完畢後,所有的參數以及函數本身都會出棧。 而函數的返回值這時則被壓入堆棧。 返回值的個數將被調整爲 nresults 個, 除非 nresults 被設置成 LUA_MULTRET。 在這種情況下,所有的返回值都被壓入堆棧中。 Lua 會保證返回值都放入棧空間中。 函數返回值將按正序壓棧(第一個返回值首先壓棧), 因此在調用結束後,最後一個返回值將被放在棧頂。

這裏lua_call(L, 2, 1)是指函數有兩個參數和一個返回值。

       lua_tointeger(L, -1):表示從棧頂取得返回值。

       lua_pop(L, 1):表示從堆棧中彈出一個元素,因爲此時add函數已經執行完畢,參數和函數本身已經出棧,堆棧中只有返回值。

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    //新建虛擬機  
    lua_State *L = luaL_newstate();  
  
    //載入庫  
    luaL_openlibs(L);  
  
    //這裏執行 test.lua  Lua文件  
    luaL_dofile(L, "test.lua"); //填的是絕對路徑 
  
    //獲取 返回結果  
    lua_getglobal(L,"test");  
    printf("\n%s\n", lua_tostring(L, -1));  
  
    //一定記得關閉虛擬機  
    lua_close(L);  
  
    return 0;  
}

//待Lua調用的C註冊函數
static int add2(lua_State* L)
{
	//檢查棧中的參數是否合法,1表示Lua調用時的第一個參數(從左到右),依此類推。
	//如果Lua代碼在調用時傳遞的參數不爲number,該函數將報錯並終止程序的執行。
	double op1 = luaL_checknumber(L,1);
	double op2 = luaL_checknumber(L,2);
	//將函數的結果壓入棧中。如果有多個返回值,可以在這裏多次壓入棧中。
	lua_pushnumber(L,op1 + op2);
	//返回值用於提示該C函數的返回值數量,即壓入棧中的返回值數量。
	return 1;
}

//待Lua調用的C註冊函數。
static int sub2(lua_State* L)
{
	double op1 = luaL_checknumber(L,1);
	double op2 = luaL_checknumber(L,2);
	lua_pushnumber(L,op1 - op2);
	return 1;
}

//待Lua調用的C註冊函數。
static int l_sin (lua_State *L) {
	double d = lua_tonumber(L, 1); /* get argument */
	lua_pushnumber(L, sin(d)); /* push result */
	return 1; /* number of results */
}

int _tmain(int argc, _TCHAR* argv[])
{
	lua_State *L = luaL_newstate();
	luaL_openlibs(L);

	//將指定的函數註冊爲Lua的全局函數變量,其中第一個字符串參數爲Lua代碼
	//在調用C函數時使用的全局函數名,第二個參數爲實際C函數的指針。
	lua_register(L, "add2", add2);
	lua_register(L, "sub2", sub2);
	lua_register(L, "l_sin", l_sin);
	//在註冊完所有的C函數之後,即可在Lua的代碼塊中使用這些已經註冊的C函數了。
	luaL_dofile(L,"test.lua");   //絕對路徑名

	//if (luaL_dostring(L,testfunc))
	// printf("Failed to invoke.\n");

	//const char *buf = "print('Hello World')";
	//luaL_dostring(L,buf);

	lua_close(L);
	return 0;
}
test.lua

function show()  
    print("helloworld") 
    print(add2(1.0,2.0)) 
    print(sub2(20.1,19))
    print(l_sin(1))
end  
  
show()  



最後,我找了一篇寫的很好的博文大家可一看看:http://www.cnblogs.com/sevenyuan/p/4511808.html


---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章