lua 全局变量

版本: Lua 5.3

 

在Lua中,它将全局变量保存在一个常规的table中,这个table被称为全局环境,该table存储在名为 _G 的表中:

for i, v in pairs(_G) do 
    print(i)
end 

--[[ 
-- 为了方便查看,进行了缩行
rawequal getmetatable bit32 load dofile pairs table package loadfile
io xpcall print type _G debug rawlen tostring error assert rawget
require math select next utf8 coroutine _VERSION arg string os rawset 
tonumber collectgarbage setmetatable pcall ipairs
]]

--[[
-- 整理了部分,方便大家学习Lua C相关
------------------ lbaselib.c中 ------------------
参考文件网址:http://www.lua.org/source/5.3/lbaselib.c.html
assert collectgarbage dofile error getmetatable ipairs loadfile
load next pairs pcall print rawequal rawget rawset select 
setmetatable tonumber tostring type xpcall _G _VERSION
------------------ loadlib.c中 ------------------
参考文件网址:http://www.lua.org/source/5.3/loadlib.c.html
require module
------------------ lualib.h 中 ------------------
参考文件网址:http://www.lua.org/source/5.3/lualib.h.html
coroutine table io os string math debug package               
------------------ lstrlib.h 中 ------------------
参考文件网址:http://www.lua.org/source/5.3/lstrlib.c.html
unpack
]]

全局变量不需要声明即可使用,然而打字出错的情况可能会导致程序出现难以发现的bug。

因此我们可以添加一个对全局表不存在健的访问,提高程序的健全性:

print(g_A)                 -- nil 可能会导致程序出现难以发现的bug

-- 试图访问不存在的全局变量会报错
setmetatable(_G, {
    __newindex = function(_, n)
        error("attempt to write to undeclared variable " .. n, 2)
    end, 
    __index = function(_, n)
        error("Error: attempt to read undeclared variable " .. n, 2)
    end,
})
print(g_A)                 -- Error:attempt to read undeclared variable g_A

 

在Lua虚拟机中,用一个全局结构的global_State来管理多个lua_State。在调用luaL_newstate()时,创建一个全局的global_State和一个lua_State后,luaL_newstate会调用f_luaopen,然后f_luaopen调用init_registry来初始化注册表,其代码如下:

/*
** Create registry table and its predefined values 
** 在lstate.c中,参考代码网址:http://www.lua.org/source/5.1/lstate.c.html
*/ static void init_registry (lua_State *L, global_State *g) { TValue temp; /* 创建注册表,初始化注册表数组部分大小为LUA_RIDX_LAST */ Table *registry = luaH_new(L); sethvalue(L, &g->l_registry, registry); luaH_resize(L, registry, LUA_RIDX_LAST, 0); /* 把这个注册表的数组部分的第一个元素赋值为主线程的状态机L 这里所说的线程并非是os的线程,而是lua的状态机概念 */ /*即 registry[LUA_RIDX_MAINTHREAD] = L */ setthvalue(L, &temp, L); /* temp = L */ luaH_setint(L, registry, LUA_RIDX_MAINTHREAD, &temp); // 把注册表的数组部分的第二个元素赋值为全局表 /*即 registry[LUA_RIDX_GLOBALS] = table of globals */ /* temp = new table (global table) */ sethvalue(L, &temp, luaH_new(L)); luaH_setint(L, registry, LUA_RIDX_GLOBALS, &temp); }

在创建注册表后,会将全局表注册到脚本中,其代码如下:

// 在linit.c中,参考代码网址:http://www.lua.org/source/5.1/linit.c.html
static
const luaL_Reg loadedlibs[] = { {"_G", luaopen_base}, {LUA_LOADLIBNAME, luaopen_package}, {LUA_COLIBNAME, luaopen_coroutine}, {LUA_TABLIBNAME, luaopen_table}, {LUA_IOLIBNAME, luaopen_io}, {LUA_OSLIBNAME, luaopen_os}, {LUA_STRLIBNAME, luaopen_string}, {LUA_MATHLIBNAME, luaopen_math}, {LUA_UTF8LIBNAME, luaopen_utf8}, {LUA_DBLIBNAME, luaopen_debug}, #if defined(LUA_COMPAT_BITLIB) {LUA_BITLIBNAME, luaopen_bit32}, #endif {NULL, NULL} };

以luaopen_base为例,会吧脚本用的函数注册到全局表,代码如下:

-- 相关的函数表
static const luaL_Reg base_funcs[] = {
  {"assert", luaB_assert},
  {"collectgarbage", luaB_collectgarbage},
  {"dofile", luaB_dofile},
  {"error", luaB_error},
  {"getmetatable", luaB_getmetatable},
  {"ipairs", luaB_ipairs},
  {"loadfile", luaB_loadfile},
  {"load", luaB_load},
  /* 省略了部分代码*/ 
  {"_G", NULL},
  {"_VERSION", NULL},
  {NULL, NULL}
};

-- 
LUAMOD_API int luaopen_base (lua_State *L) {
  /* open lib into global table */
  lua_pushglobaltable(L);
  luaL_setfuncs(L, base_funcs, 0);
  /* set global _G */
  lua_pushvalue(L, -1);
  lua_setfield(L, -2, "_G");
  /* set global _VERSION */
  lua_pushliteral(L, LUA_VERSION);
  lua_setfield(L, -2, "_VERSION");
  return 1;
}

 

参考:

https://blog.csdn.net/maximuszhou/article/details/24105673?utm_source=tuicool&utm_medium=referral

 

posted @ 2018-12-14 14:21  Code~  阅读(2213)  评论(0)    收藏  举报