标签:style blog http io ar color os sp on
近期研究了一下Lua语言在解析时的一些细节,如果在C程序中执行lua脚本的话, 那么变量的作用域是非常值得关注的,这里记录一下在分析过程中得到的一些结论。(本文的描述针对的是lua-5.1.5这个版本的代码)
考察下面的两段代码:
scope.lua
1 b = 700 -- GT[‘b‘] = 700 2 local a = 9 -- 设置在栈上 3 4 function p1() -- GT[‘p1‘] = Closure B 5 m = 90 -- GT[‘m‘] = 90 6 local n = 8 -- 设置在栈上 7 print(a) -- 数据来自upval 8 print(b) -- 数据来自GT 9 end 10 11 function p2() -- GT[‘p2‘] = Closure C 12 print(m) -- 数据来自GT 13 print(n) -- nil 14 end
srv.c
1 ... 2 luaL_loadfile(L, "scope.lua"); 3 lua_pcall(L, 0, 0, 0); // 执行闭包A的字节码 4 ... 5 lua_getglobal(L, "p1"); 6 lua_pcall(L, 0, 0, 0); // 执行闭包B的字节码 7 8 lua_getglobal(L, "p2"); 9 lua_pcall(L, 0, 0, 0); // 执行闭包C的字节码 10 ...
scope.lua脚本中会生成三个闭包A、B和C,其中闭包A是由scope.lua脚本加载(luaL_loadfile)之后生成的,luaL_loadfile最终会调用f_parse来解析脚本并生成闭包A,并且闭包A的环境table会指定为L
的global table。
接下来在srv.c中第3行将会执行闭包A对应的字节码,操作包括:
可以看到变量b、p1和p2都会保存在闭包A的环境Table中,也就是L
的global table中。
在srv.c的第5行执行之后,会将闭包B设置在栈顶,接下来调用lua_pcall便会执行闭包B对应的字节码, 操作如下:
前面讲过,闭包B的环境Table和闭包A的环境Table是一致的并且都是L
的global table,因此可以得到下面的输出结果:
9 700
同样的,srv.c执行到第8行和第9行的时候会执行闭包C的字节码,变量m是从闭包C的环境Table也就是L
的global table中获取,而变量n是闭包B的局部变量,没有设置在环境Table中,也不存在于闭包C的upval中,因此结果会为空,得到的结果如下:
90 nil
现在有很多用C语言实现的服务器程序都会嵌入Lua脚本来提高开发效率,并且通过在一个Lua虚拟机中创建多个Lua线程的手段来对每个请求的处理进行区分,因此在编写Lua脚本的时候要很清楚每个变量的作用域范围,否则可能会出现数据不一致的情况,某些变量可能是被一个Lua虚拟机中的所有Lua线程共享,而某些变量只会存在于一个Lua线程独立的数据栈中。
此外,程序中很有可能还会调用一些API来更改Lua线程的global table或环境table,因此更需要特别关注。
标签:style blog http io ar color os sp on
原文地址:http://www.cnblogs.com/portl4t/p/4159282.html