LUA函数和C函数的相互调用

本文详细介绍了LUA和C语言之间的函数调用机制,包括从C调用LUA函数及从LUA调用C函数的具体步骤。通过示例代码展示了如何实现跨语言调用,并确保正确的参数传递和返回值处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 简介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()函数了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值