您的位置:首页 > 编程语言 > Lua

c++与lua的交互--表的处理

2010-10-30 16:44 453 查看
前段时间封装了一个意在跨平台,且满足自己需求的很light的LuaEngine,对于表参数和表返回值留了白,想找时间研究一下,近日终于弄好。
首先我对C++的参数和返回值做了一个封装


enum






{


SD_NUMBER = 0, // 数字类型


SD_STRING, // 字符串类型


SD_TABLE, //表


};




struct SSDTable






{


int nNum;


void* pValue;


};




// 脚本参数对象


struct SScriptParamObj






{


int nType; // 参数类型, SD_NUMBER 或者 SD_STRING




union UScriptParam // 参数值






{


int nNumber; // 数字


char szString[64]; // 字符串


SSDTable stTable;




} unValue;




SScriptParamObj()






{


memset(this, 0, sizeof(*this));


}




~SScriptParamObj()






{




}




void operator = (int nValue)






{


nType = SD_NUMBER;


unValue.nNumber = nValue;


}




void operator = (const char *str)






{


nType = SD_STRING;


unValue.szString[0] = 0;




if (str != NULL)






{


strncpy(unValue.szString, str, sizeof(unValue.szString));


}


}




void operator = ( SSDTable& pT )






{


nType = SD_TABLE;


unValue.stTable.nNum = pT.nNum;


unValue.stTable.pValue = (void *)pT.pValue;


}




};

需要细心一点的就是,对于嵌套表的处理,不用说大家也就知道了--递归。
下面的这个函数是C++调用Lua的函数,Lua函数的参数和返回值都作为C++的参数


bool CLuaScript::CallFunction(const char *szFuncName, SScriptParamObj *pIn,


int nInNum, SScriptParamObj *pRet, int nRetNum)






{


if (szFuncName == NULL)






{


return false;


}


assert(m_pManager->GetMasterState());


assert(m_pThreadState);


lua_getglobal(m_pThreadState, szFuncName);


for (int i = 0; i < nInNum; i++)






{


// 参数的三种类型


switch (pIn[i].nType)






{


case SD_NUMBER:


lua_pushnumber(m_pThreadState, pIn[i].unValue.nNumber);


break;


case SD_STRING:


lua_pushstring(m_pThreadState, pIn[i].unValue.szString);


break;


case SD_TABLE:


// 现在栈顶创建一个新的表


lua_newtable(m_pThreadState);


int nSize = pIn[i].unValue.stTable.nNum;


SScriptParamObj* pData = (SScriptParamObj*)pIn[i].unValue.stTable.pValue;


PushTable(pData, nSize);


break;


}


}


int nStatus = lua_pcall(m_pThreadState, nInNum, nRetNum, 0);




for (int i = nRetNum - 1; i >= 0; i--)






{


// 参数的三种类型,pop的顺序,完全靠直觉


switch (pRet[i].nType)






{


case SD_NUMBER:


pRet[i].unValue.nNumber = lua_tonumber(m_pThreadState, -1);


lua_pop(m_pThreadState, 1);


break;


case SD_STRING:


strcpy(pRet[i].unValue.szString, lua_tostring(m_pThreadState, -1));


lua_pop(m_pThreadState, 1);


break;


case SD_TABLE:


ReturnTable(&pRet[i]);


lua_pop(m_pThreadState, 1);


break;


}


}




if (nStatus != 0)






{


FormatError();


OutputError("Runtime Error:");


return false;


}


return true;


}

处理表作为输入参数,对于嵌套表的处理,请大家详细的看下代码就明白了


void CLuaScript::PushTable(SScriptParamObj *pIn, int nInNum)






{


for (int i = 0; i < nInNum; i++)






{


// 参数的三种类型


switch (pIn[i].nType)






{


case SD_NUMBER:


// 添加key和value,下标从1开始


lua_pushnumber(m_pThreadState, i + 1);


lua_pushnumber(m_pThreadState, pIn[i].unValue.nNumber);


lua_rawset(m_pThreadState, -3);


break;


case SD_STRING:


lua_pushnumber(m_pThreadState, i + 1);


lua_pushstring(m_pThreadState, pIn[i].unValue.szString);


lua_rawset(m_pThreadState, -3);


break;


case SD_TABLE:


lua_pushnumber(m_pThreadState, i + 1);


lua_newtable(m_pThreadState);


int nSize = pIn[i].unValue.stTable.nNum;


SScriptParamObj* pData = (SScriptParamObj*)pIn[i].unValue.stTable.pValue;


PushTable(pData, nSize);


lua_rawset(m_pThreadState, -3);


break;


}


}


}

表作为结果返回的时候,要注意下面的情况了是否返回表结构的逻辑,程序员应该知道的,如果是 表结构,请务必手动删除分配的内存,而且
在多层的嵌套表结构中,要逐层清理。大概意思就是在引擎中会new内存,而这块内存,引擎并不知道在什么时候释放,需要程序员去手动的释放


void CLuaScript::ReturnTable(SScriptParamObj* pRet)






{


// 获取到表的索引


int nNum = 0;


int nIndex = lua_gettop(m_pThreadState);


lua_pushnil(m_pThreadState);


// 先得到数组的长度


while (lua_next(m_pThreadState, nIndex) != 0)






{


nNum++;


//移除 'value' ;保留 'key' 做下一次迭代


lua_pop(m_pThreadState, 1);


}


nIndex = lua_gettop(m_pThreadState);


// 这时候栈顶还是表


lua_pushnil(m_pThreadState);


SScriptParamObj* pObject = new SScriptParamObj[nNum];


pRet->unValue.stTable.pValue = pObject;


pRet->unValue.stTable.nNum = nNum;


nNum = 0;


while (lua_next(m_pThreadState, nIndex) != 0)






{


// 'key' (索引-2) 和 'value' (索引-1)


// 只对Value感兴趣


if (lua_type(m_pThreadState, -1) == LUA_TSTRING)






{


pObject[nNum++] = lua_tostring(m_pThreadState, -1);


}


else if (lua_type(m_pThreadState, -1) == LUA_TNUMBER)






{


pObject[nNum++] = (int)lua_tonumber(m_pThreadState, -1);


}


else if (lua_type(m_pThreadState, -1) == LUA_TTABLE)






{


ReturnTable(&pObject[nNum++]);


}


else






{


nNum++;


}


//移除 'value' ;保留 'key' 做下一次迭代


lua_pop(m_pThreadState, 1);


}


}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: