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


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

structSSDTable


{
intnNum;
void*pValue;
};

//脚本参数对象
structSScriptParamObj


{
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++的参数
boolCLuaScript::CallFunction(constchar*szFuncName,SScriptParamObj*pIn,
intnInNum,SScriptParamObj*pRet,intnRetNum)


{
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;
}
处理表作为输入参数,对于嵌套表的处理,请大家详细的看下代码就明白了
voidCLuaScript::PushTable(SScriptParamObj*pIn,intnInNum)


{
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内存,而这块内存,引擎并不知道在什么时候释放,需要程序员去手动的释放
voidCLuaScript::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);
}
}