ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

lua 之 全局变量

2021-12-21 23:58:46  阅读:192  来源: 互联网

标签:LUA -- lua registry table 全局变量 luaopen


注:本篇文章从个人博客园移植而来

_G

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虚拟机

在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;
}

参考:深入理解Lua的全局变量_G以及源码实现

标签:LUA,--,lua,registry,table,全局变量,luaopen
来源: https://blog.csdn.net/qq_24726043/article/details/122076003

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有