精华内容
下载资源
问答
  • 云风 LUA源码赏析

    2018-03-16 23:31:02
    LUA源码分析 高清版,云风关于LUA源码的分析,非常精彩。
  • programming in lua 4th,lua程序设计第4版,我学第一版的时候是200多页,现在2016年出的第四版还是200多页,更新了一些内容。还有国内大神云峰编写的《lua源码鉴赏》,分享出来一块学习进步吧。
  • /* end sweep-string phase */ lua_assert(old >= g->totalbytes); g->estimate -= old - g->totalbytes; return GCSWEEPCOST; } case GCSsweep: { lu_mem old = g->totalbytes; g->sweepgc = sweeplist(L, g->...

    GC 中最繁杂的 mark 部分已经谈完了。剩下的东西很简单。今天一次可以写完。

    sweep 分两个步骤,一个是清理字符串,另一个是清理其它对象。看代码,lgc.c 573 行:

      case GCSsweepstring: {
          lu_mem old = g->totalbytes;
          sweepwholelist(L, &g->strt.hash[g->sweepstrgc++]);
          if (g->sweepstrgc >= g->strt.size)  /* nothing more to sweep? */
            g->gcstate = GCSsweep;  /* end sweep-string phase */
          lua_assert(old >= g->totalbytes);
          g->estimate -= old - g->totalbytes;
          return GCSWEEPCOST;
        }
        case GCSsweep: {
          lu_mem old = g->totalbytes;
          g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX);
          if (*g->sweepgc == NULL) {  /* nothing more to sweep? */
            checkSizes(L);
            g->gcstate = GCSfinalize;  /* end sweep phase */
          }
          lua_assert(old >= g->totalbytes);
          g->estimate -= old - g->totalbytes;
          return GCSWEEPMAX*GCSWEEPCOST;
        }

    在 GCSsweepstring 中,每步调用 sweepwholelist 清理 strt 这个 hash 表中的一列。理想状态下,所有的 string 都被 hash 散列开没有冲突,这每一列上有一个 string 。我们可以读读 lstring.c 的 68 行:

     if (tb->nuse > cast(lu_int32, tb->size) && tb->size <= MAX_INT/2)
        luaS_resize(L, tb->size*2);  /* too crowded */

    当 hash 表中的 string 数量(nuse) 大于 hash 表的列数(size) 时,lua 将 hash 表的列数扩大一倍。就是按一列一个元素来估计的。

    值得一提的是,分布执行的 GC ,在这个阶段,string 对象是有可能清理不干净的。当 GCSsweepstring 步骤中,step 间若发生以上 string table 的 hash 表扩容事件,那么 string table 将被 rehash 。一些来不及清理的 string 很有可能被打乱放到已经通过 GCSsweepstring 的表列里。一旦发生这种情况,部分 string 对象则没有机会在当次 GC 流程中被重置为白色。在某些极端情况下,即使你调用 fullgc 一次也不能彻底的清除垃圾。

    关于 string 对象,还有个小地方需要了解。lua 是复用相同值的 TString 的,且同值 string 绝对不能有两份。而 GC 的分步执行,可能会导致一些待清理的 TString 又复活。所以在它在创建新的 TString 对象时做了检查,见 lstring.c 86 行:

     if (ts->tsv.len == l && (memcmp(str, getstr(ts), l) == 0)) {
          /* string may be dead */
          if (isdead(G(L), o)) changewhite(o);
          return ts;
        }

    相同的问题也存在于 upvalue 。同样有类似检查。

    此处 GCSWEEPCOST 应该是一个经验值。前面我们知道 singlestep 返回的这个步骤大致执行的时间。这样可以让 luaC_step 这个 api 每次执行的时间大致相同。mark 阶段是按扫描的字节数确定这个值的。而每次释放一个 string 的时间大致相等(和 string 的长度无关),GCSWEEPCOST 就是释放一个对象的开销了。

    GCSsweep 清理的是整个 GCObject 链表。这个链表很长,所以也是分段完成的。记录遍历位置的指针是 sweepgc ,每次遍历 GCSWEEPMAX 个。无论遍历是否清理,开销都是差不太多的。因为对于存活的对象,需要把颜色位重置;需要清理的对象则需要释放内存。每趟 GCSsweep 的开销势必比 GCSsweepstring 大。大致估算时间为 GCSWEEPMAX*GCSWEEPCOST 。

    真正的清理工作通过 lgc.c 408 行的 sweeplist 函数进行。

    static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
      GCObject *curr;
      global_State *g = G(L);
      int deadmask = otherwhite(g);
      while ((curr = *p) != NULL && count-- > 0) {
        if (curr->gch.tt == LUA_TTHREAD)  /* sweep open upvalues of each thread */
          sweepwholelist(L, &gco2th(curr)->openupval);
        if ((curr->gch.marked ^ WHITEBITS) & deadmask) {  /* not dead? */
          lua_assert(!isdead(g, curr) || testbit(curr->gch.marked, FIXEDBIT));
          makewhite(g, curr);  /* make it white (for next cycle) */
          p = &curr->gch.next;
        }
        else {  /* must erase `curr' */
          lua_assert(isdead(g, curr) || deadmask == bitmask(SFIXEDBIT));
          *p = curr->gch.next;
          if (curr == g->rootgc)  /* is the first element of the list? */
            g->rootgc = curr->gch.next;  /* adjust first */
          freeobj(L, curr);
        }
      }
      return p;
    }

    后半段比较好理解,当对象存活的时候,调用 makewhite ;死掉则调用 freeobj 。sweeplist 的起点并不是从 rootgc 而是 sweepgc (它们的值可能相同),所以对于头节点,需要做一点调整。

    前面的 sweep open upvalues of each thread 需要做一点解释。为什么 upvalues 需要单独清理?这要从 upvalue 的储存说起。

    upvalues 并不是放在整个 GCObject 链表中的。而是存在于每个 thread 自己的 L 中(openupval 域)。为何要这样设计?因为和 string table 类似,upvalues 需要唯一性,即引用相同变量的对象只有一个。所以运行时需要对当前 thread 的已有 upvalues 进行遍历。Lua 为了节省内存,并没有为 upvalues 多申请一个指针放置额外的链表。就借用 GCObject 本身的单向链表。所以每个 thread 拥有的 upvalues 就自成一链了。相关代码可以参考 lfunc.c 53 行处的 luaF_findupval 函数。

    但也不是所有 upvalues 都是这样存放的。closed upvalue 就不再需要存在于 thread 的链表中。在 luaF_close 函数中将把它移到其它 GCObject 链中。见 lfunc.c 106 行:

      unlinkupval(uv);
          setobj(L, &uv->u.value, uv->v);
          uv->v = &uv->u.value;  /* now current value lives here */
          luaC_linkupval(L, uv);  /* link upvalue into `gcroot' list */

    另,某些 upvalue 天生就是 closed 的。它们可以直接通过 luaF_newupval 构造出来。

    按道理来说,对 openvalues 的清理会增加单次 **sweeplist 的负荷,当记入 singlestep 的返回值。但这样会导致 sweeplist 接口变复杂,实现的代价也会增加。鉴于 thread 通常不多,GC 开销也只是一个估算值,也就没有特殊处理了。


    GC 的最后一个流程为 GCSfinalize 。

    它通过 GCTM 函数,每次调用一个需要回收的 userdata 的 gc 元方法。见 lgc.c 的 446 行:

    static void GCTM (lua_State *L) {
      global_State *g = G(L);
      GCObject *o = g->tmudata->gch.next;  /* get first element */
      Udata *udata = rawgco2u(o);
      const TValue *tm;
      /* remove udata from `tmudata' */
      if (o == g->tmudata)  /* last element? */
        g->tmudata = NULL;
      else
        g->tmudata->gch.next = udata->uv.next;
      udata->uv.next = g->mainthread->next;  /* return it to `root' list */
      g->mainthread->next = o;
      makewhite(g, o);
      tm = fasttm(L, udata->uv.metatable, TM_GC);
      if (tm != NULL) {
        lu_byte oldah = L->allowhook;
        lu_mem oldt = g->GCthreshold;
        L->allowhook = 0;  /* stop debug hooks during GC tag method */
        g->GCthreshold = 2*g->totalbytes;  /* avoid GC steps */
        setobj2s(L, L->top, tm);
        setuvalue(L, L->top+1, udata);
        L->top += 2;
        luaD_call(L, L->top - 2, 0);
        L->allowhook = oldah;  /* restore hooks */
        g->GCthreshold = oldt;  /* restore threshold */
      }
    }

    代码逻辑很清晰。需要留意的是,gc 元方法里应避免再触发 GC 。所以这里采用修改 GCthreshold 为比较较大值来回避。这其实不能完全避免 GC 的重入。甚至用户错误的编写代码也可能主动触发,但通常问题不大。因为最坏情况也只是把 GCthreshold 设置为一个不太正确的值,并不会引起逻辑上的错误。

    后记:

    终于把这个系列写完了。接下来的工作,我想做一些分析,看能否以最小代价(尽量少用锁)改造出一个多线程版本的 GC 。

    展开全文
  • 云风lua面向对象 云风wiki: https://blog.codingnow.com/cloud/LuaOO local _class={} function class(super) local class_type = {} class_type.ctor = false class_type.super = super class_type.new=...


    一. 云风lua面向对象

    云风wiki: https://blog.codingnow.com/cloud/LuaOO

    local _class={}
     
    function class(super)
    	local class_type = {}
    	class_type.ctor = false
    	class_type.super = super
    	class_type.new=function(...) 
    			local obj={}
    			do
    				local create
    				create = function(c,...)
    					if c.super then
    						create(c.super,...)
    					end
    					if c.ctor then
    						c.ctor(obj,...)
    					end
    				end
     
    				create(class_type,...)
    			end
    			setmetatable(obj,{ __index=_class[class_type] })
    			return obj
    		end
    	local vtbl={}
    	_class[class_type]=vtbl
     
    	setmetatable(class_type,{__newindex=
    		function(t,k,v)
    			vtbl[k]=v
    		end
    	})
     
    	if super then
    		setmetatable(vtbl,{__index=
    			function(t,k)
    				local ret=_class[super][k]
    				vtbl[k]=ret
    				return ret
    			end
    		})
    	end
     
    	return class_type
    end
    

    类定义

    base_type = class()		-- 定义一个基类 base_type
     
    function base_type:ctor(x)	-- 定义 base_type 的构造函数
    	print("base_type ctor")
    	self.x=x
    end
     
    function base_type:print_x()	-- 定义一个成员函数 base_type:print_x
    	print(self.x)
    end
     
    function base_type:hello()	-- 定义另一个成员函数 base_type:hello
    	print("hello base_type")
    end
    
    test=class(base_type)	-- 定义一个类 test 继承于 base_type
     
    function test:ctor()	-- 定义 test 的构造函数
    	print("test ctor")
    end
     
    function test:hello()	-- 重载 base_type:hello 为 test:hello
    	print("hello test")
    end
    

    类使用

    a = test.new(1)	-- 输出两行,base_type ctor 和 test ctor 。这个对象被正确的构造了。
    a:print_x()	-- 输出 1 ,这个是基类 base_type 中的成员函数。
    a:hello()	-- 输出 hello test ,这个函数被重载了。
    

    二. 知识点

    1. __index

    __index用于查询,当取一个table的不存在的字段时会触发,可以帮助我们解决table中字段的默认值问题。
    如果要继承某个模块,使用

    setmetatable(obj, {__index = XXX})
    

    XXXX为希望继承的模块名。

    2. __newindex

    __newindex用于更新,比如监测给table中不存在的字段的赋值。
    __newindex元方法被调用的时候会传入3个参数:table本身、字段名、想要赋予的值。

    setmetatable(obj, { __newindex = 
        function(t, k, v) 
           -- TODO
        end
        })
    

    接下来我们来解析一下上面云风大神的lua代码

    三. 代码解析

    -- _class用来保存所有类模板
    local _class = {}
    
    -- 此方法用于定义类,super为基类
    function class(super)
    	-- class_type 可以理解为类模板
    	local class_type = {}
    	-- ctor为构造函数
    	class_type.ctor = false
    	-- 赋值基类
    	class_type.super = super
    	-- 定义new成员方法
    	class_type.new = function(...) 
    			local obj = {}
    			do
    			    -- create 用于实现嵌套调用,目的是调用基类的ctor函数,即基类的构造函数
    				local create
    				create = function(c,...)
    					if c.super then
    					   -- 如果有基类,优先调用基类的ctor函数
    						create(c.super, ...)
    					end
    					if c.ctor then
    						-- 调用构造函数
    						c.ctor(obj, ...)
    					end
    				end
     
    				create(class_type, ...)
    			end
    			-- obj继承_class[class_type],其实就是下面的vtbl,obj就是类对象
    			setmetatable(obj, { __index = _class[class_type] })
    			-- new方法返回obj对象
    			return obj
    		end
    		
    	-- vtbl可以理解为类容器
    	local vtbl = {}
    	_class[class_type] = vtbl
    	
        -- class_type 新增成员的时候,存到vtbl中
    	setmetatable(class_type, { __newindex=
    		function(t, k, v)
    			vtbl[k] = v
    		end
    	})
     
    	if super then
    	    -- 如果有基类,取某个成员的时候,先从_class中找到基类容器,然后从基类容器中取成员赋值给vtbl
    	    -- 意思就是,如果子类有成员,则直接调用,否则从基类中找成员调用
    		setmetatable(vtbl, { __index = 
    			function(t, k)
    				local ret = _class[super][k]
    				vtbl[k] = ret
    				return ret
    			end
    		})
    	end
     
        -- 返回类模板,可以添加ctor函数,可以添加成员函数,这些都会被加到vtbl中,
        -- 当执行new方法的时候,就会执行vtbl的ctor函数,返回obj
        -- 执行成员方法的时候,就会执行obj的成员方法,因为obj继承了vtbl,所以会执行vtbl的成员方法
        -- 如果vtbl没有成员方法,则从其基类中查找
    	return class_type
    end
    
    展开全文
  • 云风写的Lua源码欣赏,基于lua5.2版本源代码解析,对于初初学习lua语言的有很不错的帮助
  • 我的cocos2d-x-3.2集成云风pbc lua binding方法 八月 19, 2014 | Posted by K-Res 关于protobuf的cocos2d-x lua的集成,参考过网上的一些资料,考虑过用google官方实现,但感觉过于臃肿,且没有直接的lua接口...

    我的cocos2d-x-3.2集成云风pbc lua binding方法

    关于protobufcocos2d-x lua的集成,参考过网上的一些资料,考虑过用google官方实现,但感觉过于臃肿,且没有直接的lua接口,实际应用需要做的框架级的工作较多,再有就是protoc-gen-lua(https://code.google.com/p/protoc-gen-lua/),这个感觉就比较轻量了,但是还是有需要proto转换lua的前置操作,另外就是据说某些protobuf的使用方式还不被支持,最后发现了云风做的一个实现:pbchttps://github.com/cloudwu/pbc)感觉思路很不错,而且有lua binding,决定尝试下cocos2d-x的集成。

    参考百度到的两篇文章:

    cocos2d-x 3.1 集成 云风pbc – http://blog.csdn.net/kaitiren/article/details/28865349

    在Quick-cocos2d-x中使用云风pbc解析Protocol Buffers – http://www.cnblogs.com/Erainbj/p/3618535.html

    发现这些集成方法都是对cocos2d-x框架部分做了修改,可以说是直接从引擎底层进行了整合,而我则希望以上层应用代码的角度进行整合,这样在引擎升级时和其它项目复用时都能方便一些。

    首先从最没有问题的平台入手,Mac和iOS,直接在Xcode项目中加入pbc的src和lua binding的pbc-lua.c并且设置好include搜索路径,当然,也可以用pbc源码中的Xcode项目预编译成库文件再引入,我还是倾向于对开源项目进行源代码整合,这样一旦发现问题还可以方便进行调试。然后在lua引擎加载入口脚本之前(默认是AppDelegate.cpp中),也就是

    lua_State* lState = engine->getLuaStack()->getLuaState();

    之后,加入pbc的lua函数注册:luaopen_protobuf_c(lState)。最后记得把protobuf.lua复制到cocos2d-x可以找到的位置,然后按着示例用.pb测试就可以了。

    然后是Win平台,使用VS2013,添加好include还有所有src的引用编译后,遇到了编译不能通过的问题,看了一下错误,发现pbc的.c在VS中不能按C代码编译,而应该按照C++编译,在所有.c的属性页中的“C/C++ => 高级”中,设置“编译为C++代码”后编译通过。

    最后是Android平台,按照项目结构和pbc源码的位置设置好mk文件中的src和include后,编译ok,但是运行时却出现了注册.pb文件出错的问题,看了一下pbc的lua代码,发现注册.pb文件是通过lua函数库中的io.open进行文件读取的,而cocos2d-x中的这部分的lua实现并没有重写过,就是直接封装的fopen, fread, fclose等,这样自然无法读取到被打包进Android asset文件夹中的.pb文件了!最开始考虑使用cocos2d-x的FileUtils替换掉pbc-lua中的io.open加载文件,想法就是既不修改cocos2d-x框架层的io.open实现,也不去重写pbc-lua的文件io操作,尽量都在用户应用层解决。看了一下FileUtils的lua导出,发现能够进行文件读取操作的只有一个getStringFromFile可以用,测试了一下发现还是不能正常完成pbc-lua的注册pb操作,断点调试了一下FileUtils的getStringFromFile以及pbc-lua的相关实现代码,发现问题出在文件读取后的数据传递给lua的过程中,由于cocos2d-x直接实现getStringFromFile的lua-binding中,对加载后的const char*进行了lua_pushlstring(L, s, strlen(s))的操作(由tolua的封装间接调用),而就是因为最后的strlen,导致读取.pb二进制文件时,错误的以文件中的0作为字符串结束标记错误的传递了整个二进制文件的长度,最终导致pbc-lua register时的错误。明确问题后解决就好办了,自己注册一个通过FileUtils实现的专门负责io二进制文件的c函数给lua调用:

    1 static int bsReadFile(lua_State *L)
    2 {
    3 const char *buff = luaL_checkstring(L, -1);
    4 Data data = CCFileUtils::getInstance()-&gt;getDataFromFile(buff);
    5 lua_pushlstring(L, (const char*)data.getBytes(), data.getSize());
    6 return 1; /* number of results */
    7 }
    8  
    9 ...
    10  
    11 lua_register(tolua_S, "bsReadFile", bsReadFile);

    然后在pbc-lua注册pb时使用自己的io方法:

    1 pb = require "protobuf"
    2 local pbFilePath = cc.FileUtils:getInstance():fullPathForFilename("res/addressbook.pb")
    3 cclog("PB file path: "..pbFilePath)
    4 -- local f = assert(io.open(pbFilePath , "rb"))
    5 -- local buffer = f:read "*a"
    6 local buffer = bsReadFile(pbFilePath)
    7 pb.register(buffer)
    8 -- f:close()

    这样Android上就可以正常加载asset中的.pb文件了。

    最后的最后,还有一个小问题,就是之前提到的VS需要将pbc的.c作为C++代码编译,这样就产生了一个问题:在其他平台上都是c方式编译的生成的符号都是c规范的,而win平台上则是c++规范的符号,用一样的调用代码的话,会导致找链接时找不到符号的问题,这个我的解决方法是分平台编译:

    1 extern
    2 #if CC_TARGET_PLATFORM != CC_PLATFORM_WIN32
    3 "C"
    4 #endif
    5 int luaopen_protobuf_c(lua_State *L);

    在win平台上以c++方式引用,其它平台以c方式引用。

    展开全文
  • 转自:... 关于protobuf的cocos2d-xlua的集成,参考过网上的一些资料,考虑过用google官方实现,但感觉过于臃肿,且没有直接的lua接口,实际应用需要做的框架级的工作较多,再有就是protoc-gen-lua...

    转自:http://blog.csdn.net/wanglang3081/article/details/44228475

    关于protobufcocos2d-xlua的集成,参考过网上的一些资料,考虑过用google官方实现,但感觉过于臃肿,且没有直接的lua接口,实际应用需要做的框架级的工作较多,再有就是protoc-gen-luahttps://code.google.com/p/protoc-gen-lua/),这个感觉就比较轻量了,但是还是有需要proto转换lua的前置操作,另外就是据说某些protobuf的使用方式还不被支持,最后发现了云风做的一个实现:pbchttps://github.com/cloudwu/pbc)感觉思路很不错,而且有lua binding,决定尝试下cocos2d-x的集成。

    参考百度到的两篇文章:

    cocos2d-x 3.1 集成 云风pbc – http://blog.csdn.net/kaitiren/article/details/28865349

    在Quick-cocos2d-x中使用云风pbc解析Protocol Buffers – http://www.cnblogs.com/Erainbj/p/3618535.html

    发现这些集成方法都是对cocos2d-x框架部分做了修改,可以说是直接从引擎底层进行了整合,而我则希望以上层应用代码的角度进行整合,这样在引擎升级时和其它项目复用时都能方便一些。

    首先从最没有问题的平台入手,Mac和iOS,直接在Xcode项目中加入pbc的src和lua binding的pbc-lua.c并且设置好include搜索路径,当然,也可以用pbc源码中的Xcode项目预编译成库文件再引入,我还是倾向于对开源项目进行源代码整合,这样一旦发现问题还可以方便进行调试。然后在lua引擎加载入口脚本之前(默认是AppDelegate.cpp中),也就是

    lua_State* lState = engine->getLuaStack()->getLuaState();

    之后,加入pbc的lua函数注册:luaopen_protobuf_c(lState)。最后记得把protobuf.lua复制到cocos2d-x可以找到的位置,然后按着示例用.pb测试就可以了。

    然后是Win平台,使用VS2013,添加好include还有所有src的引用编译后,遇到了编译不能通过的问题,看了一下错误,发现pbc的.c在VS中不能按C代码编译,而应该按照C++编译,在所有.c的属性页中的“C/C++ => 高级”中,设置“编译为C++代码”后编译通过。

    最后是Android平台,按照项目结构和pbc源码的位置设置好mk文件中的src和include后,编译ok,但是运行时却出现了注册.pb文件出错的问题,看了一下pbc的lua代码,发现注册.pb文件是通过lua函数库中的io.open进行文件读取的,而cocos2d-x中的这部分的lua实现并没有重写过,就是直接封装的fopen, fread, fclose等,这样自然无法读取到被打包进Android asset文件夹中的.pb文件了!最开始考虑使用cocos2d-x的FileUtils替换掉pbc-lua中的io.open加载文件,想法就是既不修改cocos2d-x框架层的io.open实现,也不去重写pbc-lua的文件io操作,尽量都在用户应用层解决。看了一下FileUtils的lua导出,发现能够进行文件读取操作的只有一个getStringFromFile可以用,测试了一下发现还是不能正常完成pbc-lua的注册pb操作,断点调试了一下FileUtils的getStringFromFile以及pbc-lua的相关实现代码,发现问题出在文件读取后的数据传递给lua的过程中,由于cocos2d-x直接实现getStringFromFile的lua-binding中,对加载后的const char*进行了lua_pushlstring(L, s, strlen(s))的操作(由tolua的封装间接调用),而就是因为最后的strlen,导致读取.pb二进制文件时,错误的以文件中的0作为字符串结束标记错误的传递了整个二进制文件的长度,最终导致pbc-lua register时的错误。明确问题后解决就好办了,自己注册一个通过FileUtils实现的专门负责io二进制文件的c函数给lua调用:

    static int bsReadFile(lua_State *L)
    {
    const char *buff = luaL_checkstring(L, -1);
    Data data = CCFileUtils::getInstance()-&gt;getDataFromFile(buff);
    lua_pushlstring(L, (const char*)data.getBytes(), data.getSize());
    return 1; /* number of results */
    }
    
    ...
    
    lua_register(tolua_S, "bsReadFile", bsReadFile);
    

    然后在pbc-lua注册pb时使用自己的io方法:

    pb = require "protobuf"
    local pbFilePath = cc.FileUtils:getInstance():fullPathForFilename("res/addressbook.pb")
    cclog("PB file path: "..pbFilePath)
    -- local f = assert(io.open(pbFilePath , "rb"))
    -- local buffer = f:read "*a"
    local buffer = bsReadFile(pbFilePath)
    pb.register(buffer)
    -- f:close()
    

    这样Android上就可以正常加载asset中的.pb文件了。

    最后的最后,还有一个小问题,就是之前提到的VS需要将pbc的.c作为C++代码编译,这样就产生了一个问题:在其他平台上都是c方式编译的生成的符号都是c规范的,而win平台上则是c++规范的符号,用一样的调用代码的话,会导致找链接时找不到符号的问题,这个我的解决方法是分平台编译:

    extern
    #if CC_TARGET_PLATFORM != CC_PLATFORM_WIN32
    "C"
    #endif
    int luaopen_protobuf_c(lua_State *L);
    

    在win平台上以c++方式引用,其它平台以c方式引用。

    展开全文
  • 以上是基本的 class 定义的语法,完全兼容 lua 的编程习惯。我增加了一个叫做 ctor 的词,作为构造函数的名字。 下面看看怎样继承: test = class ( base_type ) -- 定义一个类 test 继承于 base_type   ...
  • lua源码鉴赏云风

    2015-11-07 09:49:53
    云风写的,讲了一些实现的细节,适合想要深入的朋友,分就不要了,没分的也可以下
  • Lua5.3云风

    2017-01-07 22:41:21
    http://cloudwu.github.io/lua53doc/manual.html#2.1
  • OSTC开源技术大会分会场三:简悦科技 CTO云风,演讲主题《基于Lua开发网络游戏》
  • 云风此人,我从未见过,但是游戏界,他的传闻还是很多的,这个是他对于lua这个脚本语言的一个原理分析,我受益良多。
  • Lua 5.3 参考手册(云风)

    2018-02-10 11:53:53
    Lua 5.3 参考手册 作者 Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes 译者 云风 制作 Kavcc
  • 云风的 BLOG- 采访 Lua 发明人的一篇文章,Lua 的设计理念
  • lua源码导读---云风

    热门讨论 2012-12-13 13:54:43
    云风新作-----lua源码导读。目前网上最好的lua源代码阅读教程。帮助你快速理解lua实现原理。
  • lua 里其实也颇多奇技淫巧,使用时应三思。如果你读过 kepler 的代码,就会发现,多次编译这种技巧用的很多,甚至迭代几次使用。即,第一次加载代码时,用一段 lua 程序生成真正需要的源代码,然后再将其编译出来。...
  • LUA相关资料链接网址 作者 内容网址 沐枫小筑 Lua脚本语法说明 云风 Lua wiki lua网址 site tolua++   luaplus 相关介绍
  • 云风的 BLOG: MongoDB 的 Lua Driver 云风的 BLOG: MongoDB 的 Lua Driver posted on 2015-09-...
  • Lua源码欣赏2012年11月-云风.pdf
  • 我们可以在系统的 Lua 环境中以 Lua 库的形式再嵌入一个修改过的 Lua 解析器,用这个支持汉字变量名的解析器来解析从策划表格中读出来的脚本,生成 bytecode ,然后再在母体中运行它们。正好之前制作了一个多 State ...

空空如也

空空如也

1 2 3 4 5 ... 19
收藏数 368
精华内容 147
关键字:

云风lua