4

Lua スクリプトから呼び出される関数を C 言語で実装します。

この関数は、引数として lua テーブルを受け取る必要があるため、テーブル内のフィールドを読み取る必要があります。誰でも問題を見つけるのを手伝ってもらえますか?


/*
 function findImage(options)
    imagePath = options.imagePath
    fuzzy = options.fuzzy
    ignoreColor = options.ignoreColor;


 end

 Call Example:

  findImage {imagePath="/var/image.png", fuzzy=0.5, ignoreColor=0xffffff}

 */


// implement the function by C language
static int findImgProxy(lua_State *L)
{
    luaL_checktype(L, 1, LUA_TTABLE);

    lua_getfield(L, -1, "imagePath");
    if (!lua_isstring(L, -1)) {
        error();
    }
    const char * imagePath = lua_tostring(L, -2);
    lua_pop(L, 1);

    lua_getfield(L, -1, "fuzzy");
    if (!lua_isnumber(L, -1)) {
        error();
    }
    float fuzzy = lua_tonumber(L, -2);

    lua_getfield(L, -1, "ignoreColor");
    if (!lua_isnumber(L, -2)) {
        error();
    }
    float ignoreColor = lua_tonumber(L, -2);

    ...

    return 1;
}

CからLuaにテーブルを返すのはどうですか:


struct Point {
    int x, y;
}
typedef Point Point;


static int returnImageProxy(lua_State *L)
{
    Point points[3] = {{11, 12}, {21, 22}, {31, 32}};

    lua_newtable(L);

    for (int i = 0; i  3; i++) {
        lua_newtable(L);
        lua_pushnumber(L, points[i].x);
        lua_rawseti(L, -2, 0);
        lua_pushnumber(L, points[i].y);
        lua_rawseti(L, -2, 1);
        lua_settable(L,-3);
    }

    return 1;   // I want to return a Lua table like :{{11, 12}, {21, 22}, {31, 32}}
}

4

1 に答える 1

13

Lua C API を使用する場合、仮想スタックの操作に慣れることが重要です。重要な言語境界の相互作用はすべて仮想スタックで行われます。コード スニペットを見ると、データを C に適切にマーシャリングしているようには見えません。

lua C 関数を作成する場合、基本的に 3 つのことを行う必要があります。

  • 入力 lua データを C で操作できるものに変換します。
  • 処理を実行するか、関数が実行する必要があることを実行します。
  • 出力結果があれば変換して lua に戻します。

例として、次のようになりますfindImgProxy

static int findImgProxy(lua_State *L)
{
  // discard any extra arguments passed in
  lua_settop(L, 1);
  luaL_checktype(L, 1, LUA_TTABLE);

  // Now to get the data out of the table
  // 'unpack' the table by putting the values onto
  // the stack first. Then convert those stack values
  // into an appropriate C type.
  lua_getfield(L, 1, "imagePath");
  lua_getfield(L, 1, "fuzzy");
  lua_getfield(L, 1, "ignoreColor");
  // stack now has following:
  //   1  = {imagePath="/var/image.png", fuzzy=0.5, ignoreColor=0xffffff}
  //   -3 = "/var/image.png"
  //   -2 = 0.5
  //   -1 = 0xffffff

  const char *imagePath = luaL_checkstring(L, -3);
  double fuzzy    = luaL_checknumber(L, -2);
  int ignoreColor = luaL_checkint(L, -1);
  // we can pop fuzzy and ignoreColor off the stack
  // since we got them by value
  lua_pop(L, 2);

  // do function processing
  // ...

  return 1;
}

imagePathスタックを保持しているため、スタックを保持する必要があることに注意してくださいconst char **imagePathluaが収集する可能性があるため、その文字列をポップすると無効になります。

luaL_checkstringまたは、 によって返された文字列を別のバッファーにコピーすることもできます。この場合、lua が所有する内部バッファーを指していないので、文字列をポップしても問題ありません。

編集:表のキーの一部がオプションの場合は、luaL_opt*代わりに関数を使用してデフォルトを指定できます。たとえば、fuzzyignoreColorがオプションの場合:

  // ...
  const char *imagePath = luaL_checkstring(L, -3);
  double fuzzy    = luaL_optnumber(L, -2, 0.0); // defaults to 0.0 if no fuzzy
  int ignoreColor = luaL_optint(L, -1, 0);      // defaults to 0 if no ignoreColor
  // ...

そのため、呼び出し元のコードがキーに無意味な値を指定した場合でも、エラーが発生します。OTOH、存在しない場合、値は存在nilし、提供されたデフォルトが代わりに使用されます。

于 2013-08-28T04:38:26.253 に答える