如何从C++中过滤掉Lua中用户定义的全局变量
How to filter out user defined globals in Lua from C++?
考虑一下这个小的Lua测试脚本。
g1 = "Global 1"
g2 = "Global 2"
function test ()
local l1
print(g1,g2,l1)
end
test()
假设您在打印时暂停执行(g1,g2,l1),并从C++获得所有全局变量,代码为:
lua_pushglobaltable(L);
lua_pushnil(L);
while (lua_next(L,-2) != 0) {
const char* name = lua_tostring(L,-2);
// How do I tell a user defined
// global variable (now in name)
// from all other environment variables?
lua_pop(L,1);
}
lua_pop(L,1); // global table
当我获得全局条目的name
时,我如何判断这是否是用户在脚本中定义的全局变量,如g1和g2?
由于用户可以自由编写脚本,我无法搜索特定的全局,我需要以某种方式将它们区分开来。
我看到了两种方法。在第一个例子中,在加载用户脚本之前,记录所有全局变量的名称:
local S={}
_G["system variables"]=S
for k in pairs(_G) do S[k]=true end
然后在C代码中,遍历全局变量,并只筛选那些名称在表"system variables"
中的变量。使用lua_getglobal(L,"system variables")
获取此表。
第二种方法是,在加载系统变量后跟踪全局变量的定义。您可以通过在加载用户脚本之前运行此脚本来设置:
local U={}
_G["user variables"]=U
local function trace(t,k,v)
U[k]=true
rawset(t,k,v)
end
setmetatable(_G,{ __newindex = trace })
然后在C代码中,遍历全局变量,只筛选那些名称不在表"user variables"
中的变量。使用lua_getglobal(L,"user variables")
获取此表。
在这两种情况下,都不要将_G
中的键转换为字符串:直接使用原始键为特殊表编制索引。
请注意,您可以在遍历之前只调用lua_getglobal(L,"system variables")
或lua_getglobal(L,"user variables")
一次,并在循环中重复对其进行索引。
我的解决方案是在加载主脚本之前构建全局环境的哈希表。当我需要获得用户定义的全局变量时,我只显示哈希表中不存在的全局变量。通过这种方式,脚本可以全速运行,而无需在运行时跟踪全局变量。
我的解决方案示例(这是我实现的简短版本):
// The hash table storing global names
std::set<unsigned int> Blacklist;
// Create hash table "Blacklist"
void BlacklistSnapshot(lua_State *L) {
lua_pushglobaltable(L);
lua_pushnil(L);
while (lua_next(L,-2) != 0) { // pop NIL, push name,value
Blacklist.insert(HashName(lua_tostring(L,-2))); // insert to hash table
lua_pop(L,1); // remove value
}
lua_pop(L,1); // Remove global table
}
// Display user defined globals only
void PrintGlobals(lua_State *L) {
lua_pushglobaltable(L);
lua_pushnil(L);
while (lua_next(L,-2) != 0) { // pop NIL, push name,value
// Check if the global is present in our blacklist
if (Blacklist.find(HashName(lua_tostring(L,-2))) == Blacklist.end()) {
// Not present, print it...
PrintFormattedVariable(lua_type(L,-1),lua_tostring(L,-2));
}
lua_pop(L,1); // remove value
}
lua_pop(L,1); // remove global table
}
void RunScript(void) {
// Create new Lua state
L = luaL_newstate();
// Load all Lua libraries
luaL_openlibs(L);
// Create co-routine
CO = lua_newthread(L);
BlacklistSnapshot(CO);
// Load and compile script
AnsiString script(Frame->Script_Edit->Text);
if (luaL_loadbuffer(CO,script.c_str(),script.Length(),"Test") == LUA_OK) {
lua_resume(CO,NULL,0);
} else {
cs_error(CO, "Compiler error: "); // Print compiler error
}
}
函数HashName
获取一个字符串,并将其哈希键作为unsigned int
返回,在这里使用您喜欢的任何哈希算法。。。
当您需要显示全局时,调用PrintGlobals()
(我从hook
例程中执行)
- 创建一个函数以在输入为负数或零时输出字符串.第一次执行用户定义的函数
- 使用用户定义函数的字符串反转
- 用户定义函数中的指针和输入
- Visual C++(VS2017)中用户定义的转换不明确
- 使用用户定义的参数调用future/async并调用类方法
- 带有用户定义类的c++折叠表达式
- g++用户定义的动态链接库上的全局new和delete运算符
- 直接在 unordered_map 的方法中使用哈希,而不是生成哈希的用户定义对象
- 修改"std::set"中用户定义类型的值
- 参数包构造函数在类模板中隐藏用户定义的转换
- MAKE:找不到包含的用户定义的头文件?
- C++:用户定义的显式类型转换函数错误
- 从用户定义的类生成格式字符串?
- 为用户定义的类正确调用复制构造函数/赋值运算符
- C++ 向量与用户定义的类比较?(==, <, >)
- STL 用户定义的二进制操作
- 将用户定义的类型与 std::vector 和 std::sort 一起使用
- 为什么用户定义的函数不按照给定的顺序对相同长度的元素进行排序?
- 使用宏编译时使用用户定义的数学函数,或者仅使用 c++ 中标准数学库中的函数
- C++:用户定义的类,以成员字段作为地址