C与Lua交互之将C结构体组成table传递到Lua

概述

前面的Lua与C交互之函数注册中讲述了怎么将C函数注册到Lua中让Lua使用。
当Lua中调用C提供的获取数据的接口时,C怎么将多个结构体类型转换成Lua的嵌套table类型呢?

下面通过一个例子来讲解

例子详解

C数据类型 

typedef struct student
{
	int	 age;		///< 年龄	
	int	 grade;		///< 年级
	char name[32];	///< 姓名
}student;

typedef struct  school
{
	char phone[32];		///< 电话
	int  totalPeople;	///< 总人数
}school;

定义获取数据的接口

int get_student_info(student* p_student)
{
	assert(NULL != p_student);
	p_student->age = 8;
	p_student->grade = 3;
	strncpy(p_student->name, "XiaoMing", 32);
	
	return 0;
}

int get_school_info(school* p_school)
{
	assert(NULL != p_school);
	p_school->totalPeople = 500;
	strncpy(p_school->phone, "1008611", 32);

	return 0;
}

注册到Lua调用的接口实现

#define JL_GET_ARRAY_MAX            16          ///< 一次获取最多属性数目
#define JL_KEY_BUF_MAX              16          ///< 关键字最大缓存长度

static void format_student(lua_State *L)
{
	student student_info;
	memset(&student_info, 0, sizeof(student_info));
	int ret = get_student_info(&student_info);
	if (0 != ret)
	{
		assert(false);	
	}
	else
	{
		lua_newtable(L);
		lua_pushstring(L, student_info.name);
		lua_setfield(L, -2, "name");
	
		lua_pushinteger(L, student_info.age);
		lua_setfield(L, -2, "age");
		
		lua_pushinteger(L, student_info.grade);
		lua_setfield(L, -2, "grade");
		
		//嵌套student表到参数表中
		lua_pushstring(L, "student");
		lua_insert(L, -2); /*	student table */
		lua_settable(L, -3); /* param.student = student */
	}
}

static void format_school(lua_State *L)
{
	school school_info;
	memset(&school_info, 0, sizeof(school_info));
	int ret = get_school_info(&school_info);
	if (0 != ret)
	{
		assert(false);	
	}
	else
	{
		lua_newtable(L);
		lua_pushstring(L, school_info.phone);
		lua_setfield(L, -2, "phone");
	
		lua_pushinteger(L, school_info.totalPeople);
		lua_setfield(L, -2, "totalPeople");
				
		//嵌套school表到参数表中
		lua_pushstring(L, "school");
		lua_insert(L, -2); /*	school table */
		lua_settable(L, -3); /* param.school = school */
	}
}

//这里我们注册到Lua的函数 参数为数组{"school", "student"}
int lua_get_info(lua_State *L)
{
	luaL_checktype(L, 1, LUA_TTABLE); //检测传递过来的是否为table
	int array_len = lua_rawlen(L, 1); //数组的长度
	char keys[JL_GET_ARRAY_MAX][JL_KEY_BUF_MAX] = { 0 };
	int len_max = (array_len <= JL_GET_ARRAY_MAX) ? array_len : JL_GET_ARRAY_MAX;

	int idx = 1;
	int keys_num = 0;
	//取元素
	for (int i = 0; i < len_max; i++)
	{
		lua_rawgeti(L, 1, idx++); //取数据元素   

		size_t tmp_len = 0;
		const char* p_str = luaL_checklstring(L, -1, &tmp_len);

		if ((0 < tmp_len) && (tmp_len < JL_KEY_BUF_MAX))
		{
			strcpy(keys[keys_num], p_str);
			keys_num += 1;
		}

		lua_pop(L, 1);
	}

	//返回table	
	lua_newtable(L);

	for (int k = 0; k < keys_num; ++k)
	{
		if (0 == strcmp(keys[k], "school"))
		{
			format_school(L); //拼school table
		}
		else if (0 == strcmp(keys[k], "student"))
		{
			format_student(L); //拼student table
		}
	}

	return 1; //表明返回一个参数
}

Lua中测试代码

local b_app_api = require(app_api)
local param = b_app_api.get_info{"school", "student"}
assert(param ~= nil)
print(param.student.age, param.student.grade, param.student.name)
print(param.school.phone, param.school.totalPeople)

结果:
[LUA-print]: 8	3	XiaoMing
[LUA-print]: 1008611	500

数据数据传递简单实例

1给Lua传递数据

int num_list[] = {2, 5, 8, 3};
lua_newtable(L);
for (int i = 0; i < 4; ++i)
{
	lua_pushinteger(L, num[i]);
	lua_rawseti(L, -2, i + 1);
}
lua_pushstring(L, "num_list");
lua_insert(L, -2);
lua_settable(L, -3);

2从Lua取数组数据

luaL_checktype(L, 1, LUA_TTABLE);
int array_len = lua_rawlen(L, 1);
int *num_list = new int[array_len];
memset(num_list, 0, sizeof(int) * array_len);
for (int i = 0; i < array_len; ++i)
{
	lua_rawgeti(L, 1, i + 1);
	num_list[i] = lua_tointeger(L, -1);	
	lua_pop(L, 1);
}
//To do 

delete [] num_list;

 

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
详细描述Lua和C之间相互传递Table类型数据 /* ====================================================== */ // 遍历Lua传入的Table类型参数, 获取它的Key/Value, 其关键操作是 lua_next() // lua_next() 返回1表示读取成功,返回0表示已经没有数据可读了 // lua_next() 会使用栈顶元素作为Key去定位本次需要取出Table里面的那个值对 // 如果Key=nil, 那就表示本次取出的是第一个元素 // 它会先将当前的这个Key弹出,然后将本次取出的Key/Value压入栈, Value在栈顶 // 一个比较隐晦的处理就是, 我们不应直接使用lua_tostring(L, -2)来读取Key // 因为lua_tostring()在Key类型不是字符串时, 它会修改栈上的Key数据 // 这样, 下次调用lua_next()时, 就会因为Key被修改了而导致错误 // 为此,先调用lua_pushvalue(L, -2),将它Copy一份到栈顶,对这个Copy进行lua_tostring() // 读取Key,Value到C变量里面后,将Value和Copy弹出,留着Key在栈顶,给下次lua_next()用 // // 指令及栈图变化如下: (假如Table的栈下标是Index) // 0. 刚进入函数时 ...Table, ... <--- 这里栈顶 // 1. lua_pushnil(L) ...Table, ..., nil <--- 这里栈顶 // 2. lua_next(L, Index) ...Table, ..., Key, Value <--- 这里栈顶 // 3. lua_pushvalue(L, -2) ...Table, ..., Key, Value, KeyCopy <--- 这里栈顶 // 4. lua_pop(L, 2), ...Table, ..., Key <--- 这里栈顶 // ... 如此重复2,3,4 // N. lua_next(L, Index)返回0 ...Table, ... <--- 这里栈顶 /* ====================================================== */
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值