• Lua与C++的一些交互


    Lua调用C函数用的堆栈是临时的,调用结束之后就被销毁了.

    C调用Lua函数时,C负责堆栈.

     

    1、C++调用Lua

    调用函数的通用方法:

      1 int lua_general_call( lua_State* lua, const char* func, const char* fmt, ... )
      2 {
      3     va_list vl;
      4     int narg, nres;
      5     int len;
      6 
      7 
      8     len = lua_gettop( lua );
      9 
     10     va_start( vl, fmt );
     11 
     12     lua_getglobal( lua, func );
     13 
     14     if ( !lua_isfunction( lua, -1 ) )
     15     {
     16         fprintf( stderr, "函数不存在!\n" );
     17         goto err_exit;
     18     }
     19 
     20 
     21     narg = 0;
     22 
     23     while ( *fmt )
     24     {
     25         switch ( *fmt++ )
     26         {
     27             case 'd':
     28                 lua_pushinteger( lua, va_arg( vl, int ) );
     29                 break;
     30 
     31             case 'f':
     32                 lua_pushnumber( lua, va_arg( vl, double ) );
     33                 break;
     34 
     35             case 's':
     36                 lua_pushstring( lua, va_arg( vl, char* ) );
     37                 break;
     38 
     39             case '>':
     40                 goto endwhile;
     41 
     42             default:
     43                 fprintf( stderr, "未知参数格式!\n" );
     44                 goto err_exit;
     45         }
     46 
     47         narg ++;
     48 
     49         //栈上至少有一个空余,否则增长
     50         if ( !lua_checkstack( lua, 1 ) )
     51         {
     52             fprintf( stderr, "LUA栈空间不足!\n" );
     53             goto err_exit;
     54         }
     55     }
     56 
     57 endwhile:
     58 
     59     nres = strlen( fmt );
     60 
     61     if ( lua_pcall( lua, narg, nres, 0 ) != 0 )
     62     {
     63         fprintf( stderr, "调用错误 --- [%s]\n", lua_tostring( lua, -1 ) );
     64         goto err_exit;
     65     }
     66 
     67     nres = -nres;
     68 
     69     while ( *fmt )
     70     {
     71         switch ( *fmt++ )
     72         {
     73             case 'd':
     74                 if ( !lua_isnumber( lua, nres ) )
     75                 {
     76                     fprintf( stderr, "结果格式不对!\n" );
     77                     goto err_exit;
     78                 }
     79 
     80                 *va_arg( vl, int* ) = ( int )lua_tointeger( lua, nres );
     81                 break;
     82 
     83             case 'f':
     84                 if ( !lua_isnumber( lua, nres ) )
     85                 {
     86                     fprintf( stderr, "结果格式不对!\n" );
     87                     goto err_exit;
     88                 }
     89 
     90                 *va_arg( vl, double* ) = ( double )lua_tonumber( lua, nres );
     91                 break;
     92 
     93             case 's':
     94                 if ( !lua_isstring( lua, nres ) )
     95                 {
     96                     fprintf( stderr, "结果格式不对!\n" );
     97                     goto err_exit;
     98                 }
     99 
    100                 strcpy( va_arg( vl, char* ), lua_tostring( lua, nres ) );
    101                 break;
    102 
    103             default:
    104                 fprintf( stderr, "未知结果格式!\n" );
    105                 goto err_exit;
    106         }
    107 
    108         nres++;
    109     }
    110 
    111     va_end( vl );
    112     lua_settop( lua, len );
    113 
    114     return 0;
    115 
    116 err_exit:
    117     va_end( vl );
    118     lua_settop( lua, len );
    119     return -1;
    120 }

    Lua经常做为配置文件用

    通用方法:

     1 #define MAX_CFG_LEN               256
     2 
     3 //GUID生成
     4 static const char* g_tmp_cfg_name = "TMP_GUID";
     5 
     6 //此处cfg_name 类似于xx.xx.xx
     7 int read_cfg( lua_State* lua, const char* cfg_name, char ctt[MAX_CFG_LEN] )
     8 {
     9     int len;
    10     char str[MAX_CFG_LEN * 2];
    11 
    12     len = lua_gettop( lua );
    13     memset( str, 0, sizeof( str ) );
    14     snprintf( str, sizeof( str ), "%s = %s", g_tmp_cfg_name, cfg_name );
    15 
    16     if ( luaL_dostring( lua, str ) != 0 )
    17     {
    18         fprintf( stderr, "LUA内存不足或语法错误\n" );
    19         goto err_exit;
    20     }
    21 
    22     lua_getglobal( lua, g_tmp_cfg_name );
    23 
    24     if ( lua_type( lua, -1 ) == LUA_TNIL )
    25     {
    26         fprintf( stderr, "变量为空值\n" );
    27         goto err_exit;
    28     }
    29 
    30     snprintf( ctt, MAX_CFG_LEN, lua_tostring( lua, -1 ) );
    31 
    32     lua_settop( lua, len );
    33     return 0;
    34 
    35 err_exit:
    36     lua_settop( lua, len );
    37     return -1;
    38 }

    一般方法

    1 lua_getglobal(lua, "中文配置测试1");
    2 lua_getfield(lua, -1, "基本配置"); //键是字符串
    3 lua_pushstring(lua, "数据目录"); //任何键都可以
    4 lua_gettable(lua, -2);
    5 fprintf(stdout, "%s\n", lua_tolstring(lua, -1, NULL));

    2、Lua调用C++(LuaCallDllTest1.so)

    实质上,Lua载入SO的方式有两种:

     1 -- 方式一
     2 require("LuaCallDllTest1");
     3 --[[此句等同于:
     4 local reg_fn_tmp = package.loadlib("LuaCallDllTest1.so", "luaopen_LuaCallDllTest1");
     5 reg_fn_tmp(); -- 此函数往往为注册函数,执行一次等于注册了一个函数集
     6 --]]
     7 
     8 
     9 -- 方式二
    10 local TestFn = package.loadlib("LuaCallDllTest1.so", "lua_hello_fn");
    11 
    12 
    13 
    14 -- 方式一等同于自动注册,方式二等同于手工注册.

    C函数的撰写

      1 int lua_add(lua_State* lua)
      2 {
      3     int ret;
      4 
      5     if (lua_gettop(lua) != 2 || !lua_isnumber(lua, -1) || !lua_isnumber(lua, -2))
      6     {
      7         return 0;
      8     }
      9 
     10     ret = lua_tointeger(lua, -1) + lua_tointeger(lua, -2);
     11     lua_pushinteger(lua, ret);
     12 
     13     return 1;
     14 }
     15 
     16 int lua_avg(lua_State* lua)
     17 {
     18     int i;
     19     int len;
     20     int sum;
     21 
     22     len = lua_gettop(lua);
     23     for (sum = 0, i = 1; i <= len; i ++)
     24     {
     25         if (!lua_isnumber(lua, i))
     26         {
     27             return 0;
     28         }
     29         sum += lua_tointeger(lua, i);
     30     }
     31 
     32     lua_pushinteger(lua, sum);
     33     lua_pushnumber(lua, (double)sum / len);
     34 
     35     return 2;
     36 }
     37 
     38 // 压入表,与上面一些代码是逆过程
     39 int lua_table(lua_State* lua)
     40 {
     41     lua_newtable(lua);
     42 
     43 
     44     // 下面三行适应任何键
     45     lua_pushstring(lua, "key1");
     46     lua_pushstring(lua, "Value1");
     47     lua_settable(lua, -3);
     48 
     49     // 下面二行只适应字符串键
     50     lua_pushinteger(lua, 66666);
     51     lua_setfield(lua, -2, "key2");
     52 
     53     {
     54         lua_newtable(lua);
     55         lua_pushnumber(lua, 3.1415926);
     56         lua_setfield(lua, -2, "key31");
     57     }
     58     
     59     lua_setfield(lua, -2, "subtable");
     60 
     61     return 1;
     62 }
     63 
     64 
     65 // 压入闭包
     66 int _my_counter(lua_State *lua)
     67 {
     68     int val;
     69     int dir;
     70 
     71     //取UPVALUE值
     72     val = lua_tointeger(lua, lua_upvalueindex(1));
     73     dir = lua_tointeger(lua, lua_upvalueindex(2));
     74     //把第一个UPVALUE值处理后压栈,该值用于返回
     75     if (dir == 0)
     76     {
     77         lua_pushinteger(lua, ++ val);
     78     }
     79     else
     80     {
     81         lua_pushinteger(lua, -- val);
     82     }
     83     
     84     //COPY该栈顶 该值用于更新UPVALUE
     85     lua_pushvalue(lua, -1);
     86     //弹出栈顶元素,覆盖第一个UPVALUE 即更新UPVALUE
     87     lua_replace(lua, lua_upvalueindex(1));
     88     return 1;
     89 }
     90 
     91 int lua_counter(lua_State *lua)
     92 {
     93     int idx;
     94     int dir;
     95 
     96     //取初始值
     97     idx = lua_tointeger(lua, 1);
     98     //取方向
     99     dir = lua_tointeger(lua, 2);
    100     //UPVALUE入栈
    101     lua_pushinteger(lua, idx);
    102     lua_pushinteger(lua, dir);
    103     //指明闭包,指明UPVALUE个数
    104     lua_pushcclosure(lua, _my_counter, 2);
    105     return 1;
    106 }

    Lua调用上面相关函数

     1 require("LuaCallDllTest1");
     2 
     3 TLib = TestLuaCallLibName -- 在注册函数中注册的函数集名称
     4 
     5 MSG = TLib.TestLuaCallMsg -- 一个显示函数,上面未列出
     6 
     7 MSG('MSG From Lua');
     8 
     9 MSG(TLib.TestLuaCallAdd(1, 2)..'')
    10 MSG(TLib.TestLuaCallAvg(2, 7))
    11 
    12 local t = TLib.TestLuaCallTable('Hello World!')
    13 
    14 MSG(t.key1)
    15 MSG(t.key2..'')
    16 MSG(t.subtable.key31..'')
    17 
    18 
    19 
    20 count1 = TLib.TestLuaCallCounter(25, 1)
    21 MSG(count1())
    22 MSG(count1())
    23 MSG(count1())
    24 MSG(count1())
    25 
    26 
    27 count2 = TLib.TestLuaCallCounter(25, 0)
    28 MSG(count2())
    29 MSG(count2())
    30 MSG(count2())
    31 MSG(count2())
  • 相关阅读:
    Win10系统怎么彻底关闭Windows defender?
    用 winrar 解压 haozip 分卷压缩包的方法
    关闭WordPress自动保存和文章修订功能
    WordPress中Invalid argument supplied for foreach()错误原因及解决办法
    C#PDF转图片
    VS使用Nuget教程详解 Visual Studio 安装第三方的组件库
    kafka源码阅读环境搭建
    博客园主题美化
    官方文档
    [UGUI]UI特效裁剪
  • 原文地址:https://www.cnblogs.com/javado/p/2518735.html
Copyright © 2020-2023  润新知