程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 菜鳥入門之lua與c++相互調用(包含多個demo)

菜鳥入門之lua與c++相互調用(包含多個demo)

編輯:C++入門知識

菜鳥入門之lua與c++相互調用(包含多個demo)


前兩篇文章中,已經介紹了使用vs2010編譯lua5.1源碼生成lua.lib 和 vs項目中使用c++調用lua,可以保證demo在vs上運行起來了。這裡再詳細介紹下c++和lua之間的相互調用以及原理。

c++與lua直接的調用,實際上通過一個棧結構來傳遞數據,該棧結構棧頂的索引值為-1,向棧底方向索引值依次為-1 ,-2......棧頂索引為1.棧結構裡可以放函數,表,字符串,整形等各種lua的基本數據。

一、在當前cpp目錄下創建test.lua文件,用於與c++交互調用,代碼如下:

 

print(hello world  from lua file)
table1 = {}
table1[dinner] = rice
table1[hahha] = ri123ce
gScreenW = 1280;
function getIntegerSumFuncs(a ,b)
	return a + b
end
avg ,sum = average(10 ,20 ,30 ,40 ,50)

 

二、先熟悉下lua常用的C語言API。

int luaL_dofile (lua_State *L, const char *filename);//運行lua文件,L是當前已經創建的棧結構。返回0,運行文件正常;返回1,代表出現異常。

void lua_setglobal (lua_State *L, const char *name);//從堆棧上彈出一個值,並將其設到全局變量 name 中

void lua_getglobal (lua_State *L, const char *name);//把全局變量 name 裡的值壓入堆棧,棧頂值為-1。

const char *lua_tostring (lua_State *L, int index);//在棧L的索引值為index處取值並轉化成C字符串(lua_tointeger等類似)

void lua_settop (lua_State *L, int index);//參數允許傳入任何可接受的索引以及 0。它將把堆棧的棧頂設為這個索引。 如果新的棧頂比原來的大,超出部分的新元素將被填為 nil 。 如果 index 為 0 ,把棧上所有元素移除。

int lua_gettop (lua_State *L);//返回堆棧上的元素個數(返回 0 表示堆棧為空)

int lua_next (lua_State *L, int index);從棧上彈出一個 key(鍵), 然後把索引指定的表中 key-value(健值)對壓入堆棧 (指定 key 後面的下一 (next) 對)。 如果表中以無更多元素, 那麼 lua_next 將返回 0 (什麼也不壓入堆棧)。

void lua_pushinteger (lua_State *L, lua_Integer n);//把 n 作為一個數字壓棧。

void lua_close (lua_State *L);//銷毀指定 Lua 狀態機中的所有對象

如果需要查詢其他函數,推薦到Lua 5.1 參考手冊,很詳細也比較准確。

三、c++獲取lua中的全局字符串。

 

//獲取lua全局string
const char* getLuaGlobalString(char *fileName ,char *varName) 
{
	lua_State *L = lua_open();
	luaL_openlibs(L);
	//加載並運行test.lua文件
	int isOpen = luaL_dofile(L ,fileName); 
	if (isOpen == 0) {
		printf(error loading lua);
	}
	//將棧頂的索引設置為該index,如果index傳0,移除棧上所有元素
	lua_settop(L ,0); 
	//把全局變量 allGlobalChar 裡的值壓入堆棧。
	char *allGlobalChar = varName; 
	lua_getglobal(L ,allGlobalChar); 

	int stateCode = lua_isstring(L ,1); 
	if (stateCode != 1) {
		printf(open lua error code:%d ,stateCode);
		return NULL;
	}
	const char* s = lua_tostring(L ,1);
	printf(get global screenW is:%s 
 ,s);
	lua_pop(L ,1);
	lua_close(L);
	return s;
}
調用代碼:

 

 

getLuaGlobalString(test.lua ,gScreenW);

 

四、c++獲取lua table中的的值

 

 

const char* getLuaVarOfTable(const char *fileName,const char *tableName ,const char *keyName)
{ 
	lua_State *L = lua_open();
	luaL_openlibs(L);
	int isOpen = luaL_dofile(L ,fileName);
	if (isOpen != 0) 
	{
		printf(error open lua file);
		return NULL;
	}
	lua_settop(L ,0);//清空棧
	lua_getglobal(L ,tableName);

	int stateCode = lua_istable(L ,-1);//取棧頂
	if (stateCode != 1) 
	{
		printf(get table failed code:%d ,stateCode);
		return NULL;
	}
	lua_pushstring(L ,keyName);
	lua_gettable(L ,-2); //取棧頂下一個元素
	const char* valueStr = lua_tostring(L ,-1); //取棧頂
	printf(get lua table key-value %s-%s ,keyName ,valueStr);
	lua_pop(L ,-1);
	return valueStr;
}
調用代碼:

 

 

getLuaVarOfTable(test.lua ,table1 ,dinner);

 

五、c++獲取獲取lua中的表


string getLuaVarTable(const char* fileName ,const char *tableName ,char *result) { lua_State *L = lua_open(); luaL_openlibs(L); int isOpen = luaL_dofile(L ,fileName); if (isOpen != 0) { printf(error open lua file); return NULL; } lua_getglobal(L ,tableName); int size = lua_gettop(L); lua_pushnil(L); int index = 0; while(lua_next(L ,size)) { const char* key = lua_tostring(L ,-2);//取棧頂下一個元素 const char* value = lua_tostring(L , -1); //取棧頂 //使用memcpy ,index記錄地址游標 memcpy(&result[index] ,key ,strlen(key)); index += strlen(key); //因為sizeof取字符串,最後會有/0占一個字節,所以應該減去1 memcpy(&result[index] ,- ,sizeof(-) - 1); index += 1; memcpy(&result[index] ,value ,strlen(value)); index += strlen(value); lua_pop(L ,1); } result[index] = 0; cout <

調用代碼:

 

 

char* reslut = (char*)malloc(100 * sizeof(char));
	getLuaVarTable(test.lua ,table1 ,reslut);
	free(reslut);

 

六、cpp調用lua中的函數

 

 

//要調用一個函數請遵循以下協議: 首先,要調用的函數應該被壓入堆棧;
//	接著,把需要傳遞給這個函數的參數按正序壓棧; 這是指第一個參數首先壓棧。 
//	最後調用一下 lua_call; nargs 是你壓入堆棧的參數個數。 
//	當函數調用完畢後,所有的參數以及函數本身都會出棧。 而函數的返回值這時則被壓入堆棧。 
//	返回值的個數將被調整為 nresults 個, 除非 nresults 被設置成 LUA_MULTRET。 
//	在這種情況下,所有的返回值都被壓入堆棧中。 Lua 會保證返回值都放入棧空間中。
//	函數返回值將按正序壓棧(第一個返回值首先壓棧), 因此在調用結束後,最後一個返回值將被放在棧頂。
const char* callLuaFunc(const char* fileName ,const char* functionName)
{
	lua_State *L = lua_open();
	luaL_openlibs(L);
	int isOpen = luaL_dofile(L ,fileName);
	if (isOpen != 0) {
		printf(error open lua file %s ,fileName);
		return NULL;
	} 
	lua_getglobal(L ,functionName);//如果表和函數重名,會怎麼樣
	lua_pushinteger(L ,12);
	lua_pushinteger(L ,3);
	//第一個參數:函數的個數 第二個參數:函數的返回值個數
	lua_call(L ,2 ,1);
	int result = lua_tointeger(L ,-1);
	printf(call lua func result : %d ,result);
	return NULL;
}
調用代碼:

 

 

callLuaFunc(test.lua ,getIntegerSumFuncs);

 

七、lua調用cpp函數計算平均值

 

 

//cpp計算平均值的函數
int average(lua_State* L) 
{
	int n = lua_gettop(L);
	double sum = 0;
	int i;
	for (i = 1; i <= n; i ++)
	{
		if (!lua_isnumber(L ,i)) 
		{
			lua_pushstring(L ,incorrect argument to avg);
			lua_error(L);
		}
		sum += lua_tonumber(L ,i);
	}
	lua_pushnumber(L ,sum / n);
	lua_pushnumber(L ,sum);
	//這裡一定要返回元素個數,若返回0則找不到結果
	return 2;
}

//lua調用cpp計算平均值,調用入口
int averageMain() 
{
	lua_State* L = lua_open();
	luaL_openlibs(L);
	//注冊lua函數,實際上是將average push到棧結構,然後set average函數為global函數
	lua_register(L ,average ,average);
	//運行腳本
	luaL_dofile(L ,test.lua);

	//把全局變量 avg 裡的值壓入堆棧
	lua_getglobal(L ,avg);
	// 棧頂是-1,棧底是1
	cout << cpp show: avg is  << lua_tointeger(L ,-1) <代碼調用:
averageMain();

 

 







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