zoukankan      html  css  js  c++  java
  • LUA和C之间的函数调用

    1.1 从C程序调用LUA函数

    LUA的函数和普通变量一样也是First Class Variable类型,可以看作函数指针变量参与栈操作。因此调用过程分为如下几个步骤:
    1. 请求LUA函数(指针)入(GLOBAL)栈。
    2. 将函数需要的参数入栈,入栈顺序按照参数被声明的顺序。
    3. 告知LUA虚拟机入栈参数的个数、函数返回值的个数,并调用此LUA函数。
    4. 从栈定获得返回值,先返回的先入栈,然后将返回值显式出栈。

    1.2 从LUA脚本调用C函数

    LUA没有提供PYTHON那样丰富的类库,因此复杂的功能需要在C程序中定义好,然后通过lua决定调用时机。在LUA库中定义了可以被LUA虚拟机识别的C函数模型:
    int functionName (lua_State* L) {....; return 1;}

    这样的函数被是一个合法的lua_CFunction类型,将函数注册到LUA虚拟机中以后,就可以在LUA中以普通LUA函数的方式被调用。注册一个C函数的步骤如下:
    1. 声明并定义一个满足上述模型的函数 (eg. myFunInC)
    2. 用字符串为此C函数取一个名称并入栈(eg. myFunInLua)
    3. 将函数(指针)入栈
    4. 调用LUA库的注册函数功能,将上述的名称与函数指针关联
    这样就可以在LUA中用myFunInLua()来调用C中的int myFunInC()了

    2. 从C调用LUA函数示例

    在下面的代码中,我们调用了LUA脚本中的fnEx2函数,返回值从栈中取得,并且要手动出栈。这里,入栈的函数参数会由pcall自动清理。

    2.1 LUA测试脚本代码

    function fnex2(str_a, num_b, num_c)
        print(str_a);
        return num_b
    *100 + num_c*10"Thank you";
    end;



    2.2 VC代码

    //初始化LUA虚拟机
    void InitLuaState(lua_State* L)
    {
        
    /* Load Libraries */
        luaopen_base(L);
        luaopen_table(L);
        luaL_openlibs(L);
        luaopen_string(L);
        luaopen_math(L);
    }


    int call_lua_function(void)
    {
        
    const char* szInParam = "This is an [IN] parameter";
        
    const int iParam1 = 20, iParam2 = 50;
        cout 
    << "=================================" << endl
             
    << "02_Call_Function" << endl
             
    << "=================================" << endl
             
    << "This demo calls functions in LUA scripts." << endl
             
    << "Argument 1:" << szInParam << endl
             
    << "Argument 2:" << iParam1 << endl
             
    << "Argument 3:" << iParam2 << endl
             
    << "---------------------------------" << endl
             
    << "#OUTPUTS#" << endl;

        lua_State
    * L = lua_open();
        InitLuaState(L);

        
    int iError;

        
    /* Load Script */
        iError 
    = luaL_loadfile(L, "../test02.lua");
        
    if (iError)
        
    {
            cout 
    << "Load script FAILED!" 
                 
    << lua_tostring(L, -1)
                 
    << endl;
            lua_close(L);
            
    return 1;
        }


        
    /* Run Script */
        iError 
    = lua_pcall(L, 000);
        
    if (iError)
        
    {
            cout 
    << "pcall FAILED"
                 
    << lua_tostring(L, -1)
                 
    << iError 
                 
    << endl;
            lua_close(L);
            
    return 1;
        }

        
        
    /* Push a FUNCTION_VAR to STACK */
        lua_getglobal(L, 
    "fnex2");

        
    /* Push PARAMETERS to STACK */
        lua_pushstring(L, szInParam);
        lua_pushnumber(L, iParam1);
        lua_pushnumber(L, iParam2);

        
    /* Call FUNCTION in LUA */
        iError 
    = lua_pcall( L,    //VMachine
                            3,    //Argument Count
                            2,    //Return Value Count
                            0 );
        
    if (iError)
        
    {
            cout 
    << "pcall FAILED"
                 
    << lua_tostring(L, -1)
                 
    << iError 
                 
    << endl;
            lua_close(L);
        }


        
    /* Check Return Value Types */
        
    if (lua_isstring(L, -1&& lua_isnumber(L, -2))
        
    {
            cout 
    << "Ret_1(string): " << lua_tostring(L, -1<< endl;
            cout 
    << "Rec_2(double): " << lua_tonumber(L, -2<< endl;
        }

        
    else
        
    {
            cout 
    << "Wrong Return Values" << endl;
        }


        
    /* POP STACK */
        lua_pop(L,
    2);    //只需要清理Return Value,pcall调用的入栈参数会自动清理
        lua_close(L);
        
    return 0;
    }



    2.3 工具

    下面的宏可以简化调用lua函数的代码:
    #define CallLuaFunc(FuncName, Params, Results) 

        lua_getglobal (g_pLuaState, FuncName); 
        lua_call (g_pLuaState, Params, Results); 
    }



    3. 从LUA调用C函数示例

    在下面的例子中,我们注册一个名为rmath的LUA函数,他在C中的函数名为RMath_LUA()

    3.1 LUA脚本代码

    print (">>> LUA程序开始运行了 ");

    function fnex3(num_a, num_b)
        
    local c = rmath(num_a, num_b);
        print(
    "LUA PRINTTING:", c);
        return c;
    end;



    3.2 VC程序代码

    //LUA脚本调用C函数
    int call_c_function(void)
    {
        
    int iArg1 = 3, iArg2 = 10, iError;
        cout 
    << "=================================" << endl
             
    << "下面的程序演示从LUA脚本中调用C函数" << endl
             
    << "Argument 1:" << iArg1 << endl
             
    << "Argument 2:" << iArg2 << endl
             
    << "---------------------------------" << endl
             
    << "#OUTPUTS#" << endl;
        lua_State
    * L = lua_open();
        InitLuaState(L);

        iError 
    = luaL_loadfile(L, "../test03.lua");
        
    if (iError) cout << "载入脚本失败" << endl;

        iError 
    = lua_pcall(L, 000);
        
    if (iError) cout << "执行LUA脚本失败" << endl;

        
    /* 将C函数(指针)压栈 */
        lua_pushstring(L, 
    "rmath");
        lua_pushcfunction(L, RMath_LUA);
        lua_settable(L, LUA_GLOBALSINDEX);

        
    /* LUA函数也是变量(指针),可以压入栈 */
        lua_getglobal(L, 
    "fnex3");

        
    /* 将提供给LUA函数的参数入栈 */
        lua_pushnumber(L, iArg1);
        lua_pushnumber(L, iArg2);

        
    /* 调用LUA函数(pcall函数会自动清除入栈的变量) */
        
    int Error = lua_pcall(  L,        //虚拟机指针
                                2,        //2个参数
                                1,        //1个返回值
                                0 );

        
    if (Error) cout << "pcall调用fnex3函数失败" << endl;

        
    /* 检验返回值类型 */
        
    if (lua_isnumber(L, -1))
        
    {
            cout 
    << "有1个(double)返回值 = "
                 
    << lua_tonumber(L, -1)
                 
    << endl;
        }


        
    /* 将LUA函数返回值出栈 */
        lua_pop(L, 
    1);
        lua_close(L);
        
    return 0;
    }


    //可供LUA调用的C函数原型
    int RMath_LUA(lua_State* L)
    {
        
    if (!lua_isnumber(L, 1))
        
    {
            lua_pushstring(L, 
    "Arg_1不是数字");
            lua_error(L);
        }


        
    if (!lua_isnumber(L, 2))
        
    {
            lua_pushstring(L, 
    "Arg_2不是数字");
            lua_error(L);
        }


        
    /* GET ARGUMENT FROM STACK */
        
    double a = lua_tonumber(L, 1); 
        
    double b = lua_tonumber(L, 2);

        
    /* PUSH RESULT TO STACK */
        lua_pushnumber(L, a 
    * b);

        
    /* COUNT OF RETURN VARS*/
        
    return 1;
    }



    4. 程序解释

    4.1 调用LUA脚本中的函数

    调用LUA脚本函数主要用到如下几个LUA库函数:
        /* Push a FUNCTION_VAR to STACK */
        lua_getglobal(L, 
    "fnex2");

        
    /* Push PARAMETERS to STACK */
        lua_pushstring(L, szInParam);
        lua_pushnumber(L, iParam1);
        lua_pushnumber(L, iParam2);

        
    /* Call FUNCTION in LUA */
        iError 
    = lua_pcall( L,3,2,0);


    通过lua_getglobal请求函数(指针)入栈,然后将函数参数按声明顺序入栈,调用lua_pcall执行函数。lua_pcall的第一个参数 指向LUA虚拟机,第二个参数表示栈顶有多少个函数参数,第三个参数表示此函数将返回几个值。(pcall自动清理入栈的参数,返回值则需要手动 pop。)

    4.2 从LUA调用C函数

    主要用到如下几个函数,为求方便您也可以自己定义这样的一个宏。
        lua_pushstring(L, "rmath");
        lua_pushcfunction(L, RMath_LUA);
        lua_settable(L, LUA_GLOBALSINDEX);

    • 函数名入栈
    • lua_CFunction类型的函数指针入栈
    • 调用lua_settable注册函数
    这样就可以在lua脚本中调用rmath()函数了。
  • 相关阅读:
    17._4Csharp中正则表达式的匹配
    15.13DataGridView单元格自动填充
    C#安装,启动,停止,卸载Windows服务
    C# 如何判断系统是32位还是64位
    [转]Excel关闭进程
    利用.Net中Process类调用netstat命令来判断计算端口的使用情况
    转:C# 获取指定目录下所有文件信息、移动目录、拷贝目录
    做安装包,安装后自动运行程序
    ...
    SharpZIP Lib
  • 原文地址:https://www.cnblogs.com/hummersofdie/p/2103128.html
Copyright © 2011-2022 走看看