スポンサーリンク

C++にLuaを組み込む(3)テーブルの値の取得とスタックの状態の確認

Luaに構造体はないがテーブルがあり構造体と同じような書き方ができる。

LuaとC++の通信はLuaのスタックを介して行われるため、Luaのスタックの挙動を知っておく必要がある。

基本的な使い方

1.lua_getglobalでスクリプト内のテーブルへの参照をスタックへPush

2.lua_getfieldでテーブルへの参照から指定したキーの値をスタックへPush

3.lua_tostringでスタックの先頭の値を読み込んで表示

4.スタックをPopして次の処理に備える

#include <lua.hpp>

// lua54.dllが必要
#pragma comment(lib, "lua54.lib")

// Luaスクリプト
static const char* script = R"(
MyLuaTable ={
   val_a = "VAL_A",
   val_b = "VAL_B",
   val_c = "VAL_C",
   val_d = "VAL_D",
}
)";

int main()
{
    lua_State* luas = luaL_newstate();

    // Luaの標準ライブラリを読み込む
    luaL_openlibs(luas);

    // 文字列で与えてスクリプトを実行する
    luaL_dostring(luas, script);

    // テーブルへアクセス
    lua_getglobal(luas, "MyLuaTable");// MyLuaTableへの参照をスタックの一番上にPush
    {
        // lua_getfieldでテーブルから値を取得
        // 第一引数 ... lua_State
        // 第二引数 ... テーブルのスタック上の位置を現在のスタック位置からの差で表す
        // 第三引数 ... テーブルのキー
        /*
        * スタックの状態
        *  4 □
        *  3 □
        *  2 □ 現在位置==2。   現在位置-1 == 1。従ってlua_getfieldは'1'で参照されているテーブルから'val_a'を取り出し、ここへPushする 
        *  1 ■ MyLuaTableへの参照 lua_getglobalによりPushされている
        */
        lua_getfield(luas, -1, "val_a"); // val_aの値(現在位置からMyLuaTableまでの距離は-1)をスタックの一番上にPush
        const char* value = lua_tostring(luas, -1); // スタックの一番上の値を取得
        printf("value: %s\n", value);
        lua_pop(luas, 1/*要素を一つPOP*/);  // スタックの一番上の要素をPop。これで現在のスタック位置が2に戻る
    }

    {
        lua_getfield(luas, -1, "val_b"); // val_bの値(MyLuaTableまでの距離は-1)をスタックの一番上にPush
        const char* value = lua_tostring(luas, -1); // スタックの一番上の値を取得
        printf("value: %s\n", value);
        lua_pop(luas, 1/*要素を一つPOP*/);  // スタックの一番上の要素をPop
    }

// Luaの終了。全てのメモリ解放 lua_close(luas); }
value: VAL_A
value: VAL_B

スタックの状態確認

lua_getglobalとlua_getfieldの挙動がわからなかったので、スタックの状態を確認する。

以下のコードはスクリプトで定義されたテーブルへアクセスするために、各値をひたすらスタックへ積んでいく。

#include <lua.hpp>

// lua54.dllが必要
#pragma comment(lib, "lua54.lib")


// Luaスクリプト
static const char* script = R"(
MyLuaTable_1 ={
   val_1_a = "VAL_1_A",
   val_1_b = "VAL_1_B",
   val_1_c = "VAL_1_C",
   val_1_d = "VAL_1_D",
}

MyLuaTable_2 ={
   val_2_a = "VAL_2_A",
   val_2_b = "VAL_2_B",
   val_2_c = "VAL_2_C",
   val_2_d = "VAL_2_D",
}
)";

// Lua スタックの内容を表示
void print_stack(lua_State* luas) {

    // スタックのトップの位置を取得
    int top = lua_gettop(luas);

    // 全てのスタックの内容を表示
    // Luaのスタックは1から始まる
    for (int pos = 1; pos <= top; pos++) {
        
        int type = lua_type(luas, pos);

        printf("%d: ", pos);
        switch (type) {
        case LUA_TSTRING:
            printf("'%s'", lua_tostring(luas, pos));
            break;
        case LUA_TBOOLEAN:
            printf(lua_toboolean(luas, pos) ? "true" : "false");
            break;
        case LUA_TNUMBER:
            printf("%g", lua_tonumber(luas, pos));
            break;
        case LUA_TNIL:
            printf("nil");
            break;
        case LUA_TTABLE:
            printf("table Reference");
            break;
        case LUA_TFUNCTION:
            printf("function");
            break;
        case LUA_TUSERDATA:
            printf("userdata");
            break;
        case LUA_TTHREAD:
            printf("thread");
            break;
        case LUA_TLIGHTUSERDATA:
            printf("light userdata");
            break;
        default:
            printf("unknown");
            break;
        }
        printf("\n");
    }
}
int main()
{
    lua_State* luas = luaL_newstate();

    // Luaの標準ライブラリを読み込む
    luaL_openlibs(luas);

    // 文字列で与えてスクリプトを実行する
    luaL_dostring(luas, script);

    {
        // テーブルへアクセス
        lua_getglobal(luas, "MyLuaTable_1");// MyLuaTable_1への参照をスタックの一番上にPush
        lua_getglobal(luas, "MyLuaTable_2");// MyLuaTable_2への参照をスタックの一番上にPush

        lua_getfield(luas, -1, "val_2_a"); // val_2_aの値(MyLuaTable_2までの距離は-1)をスタックの一番上にPush
        lua_getfield(luas, -2, "val_2_b"); // val_2_bの値(MyLuaTable_2までの距離は-2)をスタックの一番上にPush
        lua_getfield(luas, -3, "val_2_c"); // val_2_aの値(MyLuaTable_2までの距離は-3)をスタックの一番上にPush
        lua_getfield(luas, -4, "val_2_d"); // val_2_bの値(MyLuaTable_2までの距離は-4)をスタックの一番上にPush
        //        [現在位置-5] にはMyLuaTable_2への参照が積まれている
        lua_getfield(luas, -6, "val_1_a"); // val_1_aの値(MyLuaTable_1までの距離は-6)をスタックの一番上にPush
        lua_getfield(luas, -7, "val_1_b"); // val_1_bの値(MyLuaTable_1までの距離は-7)をスタックの一番上にPush
        lua_getfield(luas, -8, "val_1_c"); // val_1_cの値(MyLuaTable_1までの距離は-8)をスタックの一番上にPush
        lua_getfield(luas, -9, "val_1_d"); // val_1_dの値(MyLuaTable_1までの距離は-9)をスタックの一番上にPush

    }
    print_stack(luas); // スタックの内容を表示

    // Luaの終了。全てのメモリ解放
    lua_close(luas);

}
1: table Reference
2: table Reference
3: 'VAL_2_A'
4: 'VAL_2_B'
5: 'VAL_2_C'
6: 'VAL_2_D'
7: 'VAL_1_A'
8: 'VAL_1_B'
9: 'VAL_1_C'
10: 'VAL_1_D'

スタックの値へアクセス

lua_tostringの第二引数には、スタックの先頭からの距離を指定する。-1は先頭に積まれている値を指す。例えば-4を指定すれば、先頭から4つ目の値へアクセスする。


    // テーブルへアクセス
    lua_getglobal(luas, "MyLuaTable_1");// MyLuaTable_1への参照をスタックの一番上にPush
    lua_getglobal(luas, "MyLuaTable_2");// MyLuaTable_2への参照をスタックの一番上にPush

    lua_getfield(luas, -1, "val_2_a"); // val_2_aの値(MyLuaTable_2までの距離は-1)をスタックの一番上にPush
    lua_getfield(luas, -2, "val_2_b"); // val_2_bの値(MyLuaTable_2までの距離は-2)をスタックの一番上にPush
    lua_getfield(luas, -3, "val_2_c"); // val_2_aの値(MyLuaTable_2までの距離は-3)をスタックの一番上にPush
    lua_getfield(luas, -4, "val_2_d"); // val_2_bの値(MyLuaTable_2までの距離は-4)をスタックの一番上にPush
    //        [現在位置-5] にはMyLuaTable_2への参照が積まれている
    lua_getfield(luas, -6, "val_1_a"); // val_1_aの値(MyLuaTable_1までの距離は-6)をスタックの一番上にPush
    lua_getfield(luas, -7, "val_1_b"); // val_1_bの値(MyLuaTable_1までの距離は-7)をスタックの一番上にPush
    lua_getfield(luas, -8, "val_1_c"); // val_1_cの値(MyLuaTable_1までの距離は-8)をスタックの一番上にPush
    lua_getfield(luas, -9, "val_1_d"); // val_1_dの値(MyLuaTable_1までの距離は-9)をスタックの一番上にPush

///////////////////////////////////////// // 現在位置から -4 の位置にある値を取得 const char* value = lua_tostring(luas, -4); // val_1_a の値を取得 printf("value: %s\n", value);
value: VAL_1_A

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)


この記事のトラックバックURL: