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())
原文链接: https://www.cnblogs.com/javado/archive/2012/05/25/2518735.html
欢迎关注
微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍
原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/51095
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!