在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
原文链接:http://www.manew.com/thread-89354-1-1.html 作者:周玉杰 结合这篇博客看会比较容易理解,作者:秦元培,
链接:http://blog.csdn.net/qinyuanpei/article/details/39910099
自从ulua在官网上出来后,lua 就被u3d开发人员喜爱。国内有几个高手把lua拿过来 接着进行了封装。很多都是新手转过来。lua语法一看遍知,但是大多数人还是不明白两个语言之间的互相调用是怎么一回事,这也是难点和重点。所以今天想跟大家分享一下这方面的知识,让大家少走弯路吧。
先看看u3d 里面c# 调用lua 是c# 先调用了lua的dll它是一个C库这个C库又调用了lua的东西这样才实现了c#和lua的一个通信.
所以我们先来分析一下c与lua:
C与lua交互面临以下几个问题:
1, 由于lua里面的数据都是动态加载的所以内存也是动态分配的,也没有static 这样的修饰,而C里面有 static const 这样的静态类型数据
2, c里面是手动管理内存lua 里面是自动管理内存
所以为了解决这些问题就采用了一个抽象栈来让lua与c交换值,好比c里面的 void* 可以指向任何地址而不用管存储类型。这样两边都不管你传的何种类型的参数,只用知道它是一个地址指针。两边用的时候再强制转换成对应的类型。
我们看一下C调用lua示例:
在lua中定义一个table :
background = {r=0.30, g=0.10, b=0}
在c中这样取这些值
#define MAX_COLOR 255
先定义了一个函数 供以下使用:
int getfield (const char *key) {
int result;
lua_pushstring(L, key);
//将参数 key 栈为2或者-1入栈
lua_gettable(L, -2);
// 它会将栈顶做为key并将value返回到栈顶
if (!lua_isnumber(L, -1)) //栈顶值判断是否是一个数字
error(L, "invalid component in background color");
result = (int)lua_tonumber(L, -1) * MAX_COLOR;
//将返回的栈顶值拿来进行强制转换 int
lua_pop(L, 1); /* remove number */
return result;
}
这是咱们lua程序的起始位置 假设前面的lua环境已经加载好了:
lua_getglobal(L, "background");
// 这句话将lua 表background获取放在栈 1的位置
if (!lua_istable(L, -1))
error(L, "`background' is not a valid color table");
red = getfield("r");
green = getfield("g");
blue = getfield("b");
具体分析:
第一步: lua_getglobal(L, "background");
//这句话将lua 表background获取放在栈1的位置
第二步:
getfield("r");
lua_pushstring(L, key);
//将参数“r”key栈为2或者-1入栈
第三步:
lua_gettable(L, -2);
//它会将栈顶做为key并将value返回到栈顶并去除 r
(这个地方是lua内部的协议就会默认的将表以上的栈作为参数key传入并返回值将key去除)
第四步:
result = (int)lua_tonumber(L, -1) * MAX_COLOR;
//将返回的栈顶值拿来进行强制转换 int
第五步:
lua_pop(L, 1);
//将栈顶也就是result进行剔除栈
这样 c 就拿到了变量 red
注意:
栈索引既可以是正数索引也可以是负数, 正数最底下的为1最上面的为-1
lua_gettable(L, -2);
//这个地方是lua内部的协议:
1,表以上的栈作为参数key传入
2,将key从栈中去除
3,并返回值放入栈顶
这是lua跟C传参的内置协议大家要明白了它就会有这么几步操作。
lua 调用C :
第一步:定义c函数
向lua注册的函数必须要有这样的结构返回值为int传入参数为lua_State*
typedef int (*lua_CFunction) (lua_State *L);
所以:
static int l_sin (lua_State *L) {
double d = lua_tonumber(L, 1);
/*第一个参数总是在这个私有栈的index=1的位置//获取参数 */
lua_pushnumber(L, sin(d));
/* 第结果放入栈中 */
return 1;
/* number of results */
}
第二步向lua注册:
lua_pushcfunction(l, l_sin);
// 这里相信大家要知道为啥u3d里面要注册wrap文件了
lua_setglobal(l, "mysin");
第三步:lua调用:
reuslt = mysin(45)
// 取出的就是栈顶的值
分析 :
调用 reuslt = mysin(45)实则是调用:
static int l_sin (lua_State *L) {
double d = lua_tonumber(L, 1);
/* 获取参数 45 */
lua_pushnumber(L, sin(d));
/* 第结果放入栈顶就是返回给 reuslt */
return 1;
/* number of results */
}
注意:
1,每一个函数都有一个私有栈并且第一个参数就是在栈的1位置,后面以此类推有几个参数就有多少个
2,如果函数返回结果,第一个结果被第一个入栈,因此如果有n个返回结果,第一个返回结果在栈中的位置为-n,最后一个返回结果在栈中的位置为-1
c#就是在这基础之上又调用了C api所以相信大家在看c#与lua也就明白很多了。也知道为什么要进行wrap,wrap之后为什么可以直接使用了。
|
请发表评论