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


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

 struct SSDTable
struct SSDTable


 {
{
 int nNum;
    int nNum;
 void* pValue;
    void* pValue;    
 };
};

 // 脚本参数对象
// 脚本参数对象
 struct SScriptParamObj
struct SScriptParamObj


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

 union UScriptParam    // 参数值
    union UScriptParam    // 参数值

 
     {
{
 int        nNumber;        // 数字
        int        nNumber;        // 数字
 char    szString[64];    // 字符串
        char    szString[64];    // 字符串
 SSDTable stTable;
        SSDTable stTable;

 } unValue;
    } unValue;

 SScriptParamObj()
    SScriptParamObj()

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

 ~SScriptParamObj()
    ~SScriptParamObj()

 
     {
{

 }
    }

 void operator = (int nValue)
    void operator = (int nValue)

 
     {
{
 nType = SD_NUMBER;
        nType = SD_NUMBER;
 unValue.nNumber = nValue;
        unValue.nNumber = nValue;
 }
    }

 void operator = (const char *str)
    void operator = (const char *str)

 
     {
{
 nType = SD_STRING;
        nType = SD_STRING;
 unValue.szString[0] = 0;
        unValue.szString[0] = 0;

 if (str != NULL)
        if (str != NULL)

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

 void operator = ( SSDTable& pT )
    void operator = ( SSDTable& pT )

 
     {
{
 nType = SD_TABLE;
        nType = SD_TABLE;
 unValue.stTable.nNum = pT.nNum;
        unValue.stTable.nNum = pT.nNum;
 unValue.stTable.pValue = (void *)pT.pValue;
        unValue.stTable.pValue = (void *)pT.pValue;    
 }
    }

 };
};需要细心一点的就是,对于嵌套表的处理,不用说大家也就知道了--递归。
下面的这个函数是C++调用Lua的函数,Lua函数的参数和返回值都作为C++的参数
 bool CLuaScript::CallFunction(const char *szFuncName, SScriptParamObj *pIn,
bool CLuaScript::CallFunction(const char *szFuncName, SScriptParamObj *pIn, 
 int nInNum, SScriptParamObj *pRet, int nRetNum)
                              int nInNum, SScriptParamObj *pRet, int nRetNum)


 {
{
 if (szFuncName == NULL)
    if (szFuncName == NULL)

 
     {
{
 return false;
        return false;
 }
    }
 assert(m_pManager->GetMasterState());
    assert(m_pManager->GetMasterState());
 assert(m_pThreadState);
    assert(m_pThreadState);
 lua_getglobal(m_pThreadState, szFuncName);
    lua_getglobal(m_pThreadState, szFuncName);
 for (int i = 0; i < nInNum; i++)
    for (int i = 0; i < nInNum; i++)

 
     {
{
 // 参数的三种类型
        // 参数的三种类型
 switch (pIn[i].nType)
        switch (pIn[i].nType)

 
         {
{
 case SD_NUMBER:
        case SD_NUMBER:
 lua_pushnumber(m_pThreadState, pIn[i].unValue.nNumber);
            lua_pushnumber(m_pThreadState, pIn[i].unValue.nNumber);
 break;
            break;
 case SD_STRING:
        case SD_STRING:
 lua_pushstring(m_pThreadState, pIn[i].unValue.szString);
            lua_pushstring(m_pThreadState, pIn[i].unValue.szString);
 break;
            break;
 case SD_TABLE:
        case SD_TABLE:    
 // 现在栈顶创建一个新的表
            // 现在栈顶创建一个新的表
 lua_newtable(m_pThreadState);
            lua_newtable(m_pThreadState);
 int nSize = pIn[i].unValue.stTable.nNum;
            int nSize = pIn[i].unValue.stTable.nNum;    
 SScriptParamObj* pData = (SScriptParamObj*)pIn[i].unValue.stTable.pValue;
            SScriptParamObj* pData = (SScriptParamObj*)pIn[i].unValue.stTable.pValue;
 PushTable(pData, nSize);
            PushTable(pData, nSize);
 break;
            break;
 }
        }
 }
    }
 int nStatus = lua_pcall(m_pThreadState, nInNum, nRetNum, 0);
    int nStatus = lua_pcall(m_pThreadState, nInNum, nRetNum, 0);

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

 
     {
{
 // 参数的三种类型,pop的顺序,完全靠直觉
        // 参数的三种类型,pop的顺序,完全靠直觉
 switch (pRet[i].nType)
        switch (pRet[i].nType)

 
         {
{
 case SD_NUMBER:
        case SD_NUMBER:
 pRet[i].unValue.nNumber = lua_tonumber(m_pThreadState, -1);
            pRet[i].unValue.nNumber = lua_tonumber(m_pThreadState, -1);
 lua_pop(m_pThreadState, 1);
            lua_pop(m_pThreadState, 1);
 break;
            break;
 case SD_STRING:
        case SD_STRING:
 strcpy(pRet[i].unValue.szString, lua_tostring(m_pThreadState, -1));
            strcpy(pRet[i].unValue.szString, lua_tostring(m_pThreadState, -1));
 lua_pop(m_pThreadState, 1);
            lua_pop(m_pThreadState, 1);
 break;
            break;        
 case SD_TABLE:
        case SD_TABLE:
 ReturnTable(&pRet[i]);
            ReturnTable(&pRet[i]);
 lua_pop(m_pThreadState, 1);
            lua_pop(m_pThreadState, 1);
 break;
            break;
 }
        }
 }
    }

 if (nStatus != 0)
    if (nStatus != 0)

 
     {
{
 FormatError();
        FormatError();
 OutputError("Runtime Error:");
        OutputError("Runtime Error:");
 return false;
        return false;
 }
    }
 return true;
    return true;
 }
}处理表作为输入参数,对于嵌套表的处理,请大家详细的看下代码就明白了
 void CLuaScript::PushTable(SScriptParamObj *pIn, int nInNum)
void CLuaScript::PushTable(SScriptParamObj *pIn, int nInNum)


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

 
     {
{
 // 参数的三种类型
        // 参数的三种类型
 switch (pIn[i].nType)
        switch (pIn[i].nType)

 
         {
{
 case SD_NUMBER:
        case SD_NUMBER:
 // 添加key和value,下标从1开始
            // 添加key和value,下标从1开始
 lua_pushnumber(m_pThreadState, i + 1);
            lua_pushnumber(m_pThreadState, i + 1);
 lua_pushnumber(m_pThreadState, pIn[i].unValue.nNumber);
            lua_pushnumber(m_pThreadState, pIn[i].unValue.nNumber);
 lua_rawset(m_pThreadState, -3);
            lua_rawset(m_pThreadState, -3);
 break;
            break;
 case SD_STRING:
        case SD_STRING:
 lua_pushnumber(m_pThreadState, i + 1);
            lua_pushnumber(m_pThreadState, i + 1);
 lua_pushstring(m_pThreadState, pIn[i].unValue.szString);
            lua_pushstring(m_pThreadState, pIn[i].unValue.szString);
 lua_rawset(m_pThreadState, -3);
            lua_rawset(m_pThreadState, -3);
 break;
            break;
 case SD_TABLE:
        case SD_TABLE:    
 lua_pushnumber(m_pThreadState, i + 1);
            lua_pushnumber(m_pThreadState, i + 1);
 lua_newtable(m_pThreadState);
            lua_newtable(m_pThreadState);
 int nSize = pIn[i].unValue.stTable.nNum;
            int nSize = pIn[i].unValue.stTable.nNum;    
 SScriptParamObj* pData = (SScriptParamObj*)pIn[i].unValue.stTable.pValue;
            SScriptParamObj* pData = (SScriptParamObj*)pIn[i].unValue.stTable.pValue;
 PushTable(pData, nSize);
            PushTable(pData, nSize);
 lua_rawset(m_pThreadState, -3);
            lua_rawset(m_pThreadState, -3);
 break;
            break;
 }
        }
 }
    }
 }
}表作为结果返回的时候,要注意下面的情况了是否返回表结构的逻辑,程序员应该知道的,如果是 表结构,请务必手动删除分配的内存,而且
在多层的嵌套表结构中,要逐层清理。大概意思就是在引擎中会new内存,而这块内存,引擎并不知道在什么时候释放,需要程序员去手动的释放
 void CLuaScript::ReturnTable(SScriptParamObj* pRet)
void CLuaScript::ReturnTable(SScriptParamObj* pRet)


 {
{
 // 获取到表的索引
    // 获取到表的索引
 int nNum = 0;
    int nNum = 0;            
 int nIndex = lua_gettop(m_pThreadState);
    int nIndex = lua_gettop(m_pThreadState);
 lua_pushnil(m_pThreadState);
    lua_pushnil(m_pThreadState);
 // 先得到数组的长度
    // 先得到数组的长度
 while (lua_next(m_pThreadState, nIndex) != 0)
    while (lua_next(m_pThreadState, nIndex) != 0)    

 
     {
{                    
 nNum++;
        nNum++;
 //移除 'value' ;保留 'key' 做下一次迭代
        //移除 'value' ;保留 'key' 做下一次迭代
 lua_pop(m_pThreadState, 1);
        lua_pop(m_pThreadState, 1); 
 }
    } 
 nIndex = lua_gettop(m_pThreadState);
    nIndex = lua_gettop(m_pThreadState);
 // 这时候栈顶还是表
    // 这时候栈顶还是表
 lua_pushnil(m_pThreadState);
    lua_pushnil(m_pThreadState);
 SScriptParamObj* pObject = new SScriptParamObj[nNum];
    SScriptParamObj* pObject = new SScriptParamObj[nNum];
 pRet->unValue.stTable.pValue = pObject;
    pRet->unValue.stTable.pValue = pObject;
 pRet->unValue.stTable.nNum = nNum;
    pRet->unValue.stTable.nNum = nNum;
 nNum = 0;
    nNum = 0;
 while (lua_next(m_pThreadState, nIndex) != 0)
    while (lua_next(m_pThreadState, nIndex) != 0)    

 
     {
{    
 // 'key' (索引-2) 和 'value' (索引-1)
        // 'key' (索引-2) 和 'value' (索引-1)    
 // 只对Value感兴趣
        // 只对Value感兴趣
 if (lua_type(m_pThreadState, -1) == LUA_TSTRING)
        if (lua_type(m_pThreadState, -1) == LUA_TSTRING)    

 
         {
{                     
 pObject[nNum++] = lua_tostring(m_pThreadState, -1);
            pObject[nNum++] = lua_tostring(m_pThreadState, -1);    
 }
        }    
 else if (lua_type(m_pThreadState, -1) == LUA_TNUMBER)
        else if (lua_type(m_pThreadState, -1) == LUA_TNUMBER)    

 
         {
{                        
 pObject[nNum++] = (int)lua_tonumber(m_pThreadState, -1);
            pObject[nNum++] = (int)lua_tonumber(m_pThreadState, -1);   
 }
        }    
 else if (lua_type(m_pThreadState, -1) == LUA_TTABLE)
        else if (lua_type(m_pThreadState, -1) == LUA_TTABLE)

 
         {
{    
 ReturnTable(&pObject[nNum++]);
            ReturnTable(&pObject[nNum++]);
 }
        }  
 else
        else

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