从C 访问功能环境中的LUA变量

Accessing Lua variable in function environment from C++

本文关键字:LUA 变量 环境 访问 功能      更新时间:2023-10-16

这可能是一个简单的问题,但我很难过。这是针对LUA 5.1。

我有一个在自己的环境中运行的脚本。在那个环境中,我有一个称为"插件"的变量,我从c 设置了这样的变量:

    lua_getfield(L, LUA_REGISTRYINDEX, getScriptId());  // Put script's env table onto the stack  -- env_table
    lua_pushstring(L, "plugin");  //                           -- env_table, "plugin"
    luaW_push(L, this);       //                               -- env_table, "plugin", *this
    lua_rawset(L, -3);        // env_table["plugin"] = *this   -- env_table
    lua_pop(L, -1);           // Cleanup                       -- <<empty stack>>

在运行LUA脚本之前,我将功能环境设置为这样:

 lua_getfield(L, LUA_REGISTRYINDEX, getScriptId());    // Push REGISTRY[scriptId] onto stack           -- function, table
 lua_setfenv(L, -2);                                   // Set that table to be the env for function    -- function

当我的脚本运行时,它可以按预期看到并与插件变量进行交互。到目前为止,一切都很好。

在某一时刻,LUA脚本称为C 函数,在该功能中,我想看看是否设置了插件变量。

我尝试了很多事情,而且我似乎看不到插件变量。这只是我尝试的4件事:

lua_getfield(L, LUA_ENVIRONINDEX, "plugin");
bool isPlugin = !lua_isnil(L, -1);
lua_pop(L, 1);    // Remove the value we just added from the stack
lua_getfield(L, LUA_GLOBALSINDEX, "plugin");
bool isPlugin2 = !lua_isnil(L, -1);
lua_pop(L, 1);    // Remove the value we just added from the stack
lua_getglobal(L, "plugin");
bool isPlugin3 = !lua_isnil(L, -1);
lua_pop(L, 1);    // Remove the value we just added from the stack
lua_pushstring(L, "plugin");
bool isPlugin4 = lua_isuserdata(L, -1);
lua_pop(L, 1);

不幸的是,所有iSplugin变量返回false。好像来自LUA调用的C 函数无法在LUA环境中看到变量集。

知道我如何从C 看到插件变量?

谢谢!

lua中的每个函数都有其自己的环境。他们不会继承任何人称呼的环境。因此,如果您的C 函数不使用具有此plugin变量的环境,则不会看到它。

您可以将环境作为闭合的一部分传递到C函数(请参阅lua_pushcclosure)。我不知道您拥有的设置,但是我可以看到这可以解决的三种方法:

1)您的C函数在与函数相同的环境中注册 - 良好,将起作用。
2)您的C函数已在全球环境中注册,但是将其称为所有特定环境中的LUA函数 - 如果在函数注册时存在环境(可以将其添加到关闭中)。<<<<<<<<<<<<<<<<<<br>3)您的C功能已在全球环境中注册,可以通过在不同环境中工作的不同LUA函数来调用 -

如果是2或3,则如果更改使用变体1。

,可能没有缺点。

编辑:好吧,这不会起作用。如果您愿意从LUA API中差一点,则可以获得一种获取地下信息的方法。免责声明:我正在使用5.2,所以我试图以5.1的方式调整方法。我无法测试,它可能不起作用。

首先您需要#include "lstate.h"

这是5.1中的lua_state结构:

struct lua_State {
  CommonHeader;
  lu_byte status;
  StkId top;  /* first free slot in the stack */
  StkId base;  /* base of current function */
  global_State *l_G;
  CallInfo *ci;  /* call info for current function */
  const Instruction *savedpc;  /* `savedpc' of current function */
  StkId stack_last;  /* last free slot in the stack */
  StkId stack;  /* stack base */
  CallInfo *end_ci;  /* points after end of ci array*/
  CallInfo *base_ci;  /* array of CallInfo's */
  int stacksize;
  int size_ci;  /* size of array `base_ci' */
  unsigned short nCcalls;  /* number of nested C calls */
  lu_byte hookmask;
  lu_byte allowhook;
  int basehookcount;
  int hookcount;
  lua_Hook hook;
  TValue l_gt;  /* table of globals */
  TValue env;  /* temporary place for environments */
  GCObject *openupval;  /* list of open upvalues in this stack */
  GCObject *gclist;
  struct lua_longjmp *errorJmp;  /* current error recover point */
  ptrdiff_t errfunc;  /* current error handling function (stack index) */
};

假设我是您的lua_State*。如您所见,L->ci保留当前的CallInfo,CallInfo数组包含在L->base_ciL->end_ci之间。

因此,称为C函数的LUA函数位于(L->end_ci-2)(应与(L->ci-1)相同),其堆栈ID(Stkid)为(L->end_ci-2)->func。我们可以通过执行类似的操作来欺骗LUA API,让您使用堆栈ID,而堆栈ID在当前调用函数以下:

StkId saved = L->base;
L->base = L->base_ci->base;
int idx = (L->end_ci-2)->func - L->base+1;
lua_getfenv(L, idx);
L->base = saved;

现在的环境表应该位于堆栈的顶部。

编辑:有效索引的LUA API检查有点棘手。这应该欺骗他们。