4

これはおそらく簡単な質問ですが、私は困惑しています。これはLua5.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 ++からプラグイン変数を確認する方法はありますか?

ありがとう!

4

2 に答える 2

2

Luaのすべての関数には独自の環境があります。それらは、それらを呼び出す人の環境を継承しません。pluginしたがって、C ++関数がこの変数を持つ環境を使用しない場合、C++関数はそれを認識しません。

于 2012-11-08T03:58:14.940 に答える
0

クロージャの一部として環境をC関数に渡すことができます(を参照lua_pushcclosure)。あなたのセットアップの種類はわかりませんが、これがうまくいく3つの方法を見ることができます。

1)C関数が関数と同じ環境に登録されている-良い、動作します。
2)C関数はグローバル環境に登録されていますが、それを呼び出すLua関数はすべて1つの特定の環境に存在します。関数の登録時に環境が存在する場合は、引き続き機能します(クロージャーに追加できます)。
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) */
};

Lがあなたのであると仮定しましょう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を操作できるようにすることができます。

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;

これで、環境テーブルがスタックの一番上にあるはずです。

編集:LuaAPIが有効なインデックスをチェックするのは少し注意が必要です。これは彼らをだますはずです。

于 2012-11-09T04:05:21.807 に答える