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

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

enum
{
SD_NUMBER
=0,//数字类型
SD_STRING,//字符串类型
SD_TABLE,//
}
;

struct SSDTable
{
intnNum;
void*pValue;
}
;

// 脚本参数对象
struct SScriptParamObj
{
intnType;//参数类型,SD_NUMBER或者SD_STRING

unionUScriptParam
//参数值
{
intnNumber;//数字
charszString[64];//字符串
SSDTablestTable;

}
unValue;

SScriptParamObj()
{
memset(
this,0,sizeof(*this));
}


~SScriptParamObj()
{

}


voidoperator=(intnValue)
{
nType
=SD_NUMBER;
unValue.nNumber
=nValue;
}


voidoperator=(constchar*str)
{
nType
=SD_STRING;
unValue.szString[
0]=0;

if(str!=NULL)
{
strncpy(unValue.szString,str,
sizeof(unValue.szString));
}

}


voidoperator=(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)
{
returnfalse;
}

assert(m_pManager
->GetMasterState());
assert(m_pThreadState);
lua_getglobal(m_pThreadState,szFuncName);
for(inti=0;i<nInNum;i++)
{
//参数的三种类型
switch(pIn[i].nType)
{
caseSD_NUMBER:
lua_pushnumber(m_pThreadState,pIn[i].unValue.nNumber);
break;
caseSD_STRING:
lua_pushstring(m_pThreadState,pIn[i].unValue.szString);
break;
caseSD_TABLE:
//现在栈顶创建一个新的表
lua_newtable(m_pThreadState);
intnSize=pIn[i].unValue.stTable.nNum;
SScriptParamObj
*pData=(SScriptParamObj*)pIn[i].unValue.stTable.pValue;
PushTable(pData,nSize);
break;
}

}

intnStatus=lua_pcall(m_pThreadState,nInNum,nRetNum,0);

for(inti=nRetNum-1;i>=0;i--)
{
//参数的三种类型,pop的顺序,完全靠直觉
switch(pRet[i].nType)
{
caseSD_NUMBER:
pRet[i].unValue.nNumber
=lua_tonumber(m_pThreadState,-1);
lua_pop(m_pThreadState,
1);
break;
caseSD_STRING:
strcpy(pRet[i].unValue.szString,lua_tostring(m_pThreadState,
-1));
lua_pop(m_pThreadState,
1);
break;
caseSD_TABLE:
ReturnTable(
&pRet[i]);
lua_pop(m_pThreadState,
1);
break;
}

}


if(nStatus!=0)
{
FormatError();
OutputError(
"RuntimeError:");
returnfalse;
}

returntrue;
}


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

void CLuaScript::PushTable(SScriptParamObj * pIn, int nInNum)
{
for(inti=0;i<nInNum;i++)
{
//参数的三种类型
switch(pIn[i].nType)
{
caseSD_NUMBER:
//添加key和value,下标从1开始
lua_pushnumber(m_pThreadState,i+1);
lua_pushnumber(m_pThreadState,pIn[i].unValue.nNumber);
lua_rawset(m_pThreadState,
-3);
break;
caseSD_STRING:
lua_pushnumber(m_pThreadState,i
+1);
lua_pushstring(m_pThreadState,pIn[i].unValue.szString);
lua_rawset(m_pThreadState,
-3);
break;
caseSD_TABLE:
lua_pushnumber(m_pThreadState,i
+1);
lua_newtable(m_pThreadState);
intnSize=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)
{
//获取到表的索引
intnNum=0;
intnIndex=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=newSScriptParamObj[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);
}

elseif(lua_type(m_pThreadState,-1)==LUA_TNUMBER)
{
pObject[nNum
++]=(int)lua_tonumber(m_pThreadState,-1);
}

elseif(lua_type(m_pThreadState,-1)==LUA_TTABLE)
{
ReturnTable(
&pObject[nNum++]);
}

else
{
nNum
++;
}

//移除'value';保留'key'做下一次迭代
lua_pop(m_pThreadState,1);
}

}

你可能感兴趣的:(C++,c,脚本,C#,lua)