第 6 回: Lua を組み込み用の言語として利用する方法 (変数編)

関数をまとめてライブラリとして登録する

さて, 前回, C 言語の関数を Lua に登録する方法を紹介したが, これはグローバル関数として関数を登録するものだった.

今回は, MyLib.xxx のように特定のオブジェクト (テーブル) 内に複数の関数を一度に登録する方法を紹介する.

ここで定義するのは, C 言語側に MyLib.c_add() と MyLib.c_sub() という二つの関数を登録する. 以下は, Lua 側のスクリプト

func3.lua

1
2
3
4
5
6
-- func3.lua
print( MyLib.c_add(4, 3) )
print( MyLib.c_add(40, 30) )
print( MyLib.c_sub(4, 3) )
print( MyLib.c_sub(40, 30) )
print( MyLib.c_sub(400, 300) )

test3.c

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
/*
  test.c
*/
#include <stdio.h>

#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>

/* 自作関数の登録足し算 */
int c_add(lua_State *L){
  // 引数を得る
  int a1 = lua_tointeger(L, 1); // 第 1 引数を得る
  int a2 = lua_tointeger(L, 2); // 第 2 引数を得る
  lua_pushinteger(L, a1+a2);
  return 1; // 戻り値の数を返す
}

/* 自作関数の登録引き算 */
int c_sub(lua_State *L){
  int a1 = lua_tointeger(L, 1);
  int a2 = lua_tointeger(L, 2);
  lua_pushinteger(L, a1 - a2);
  return 1; // 戻り値の数を返す
}

/* 自作関数のライブラリの関数テーブルを定義 */
static const luaL_Reg MyLibTable[] = {
  {"c_add", c_add},
  {"c_sub", c_sub},
  {NULL, NULL}
};

/* エラーの表示用 */
void show_error(lua_State *L){
  const char *err = lua_tostring(L, -1);
  printf("ERROR: %s\n", err);
}

/* メイン関数 */
int main(int argc, char *argv[]){
  lua_State *L = luaL_newstate();
  luaL_openlibs(L); // Lua のライブラリを使えるようにする
  // Lua に関数群を登録する
  luaL_openlib(L, "MyLib", MyLibTable, 0);
  // Lua のスクリプトを読み込む
  if( luaL_loadfile(L, "func3.lua") || lua_pcall(L, 0, 0, 0) ){
    printf("func3.lua が読めなかった\n");
    show_error(L);
    return -1;
  }
  // 閉じる
  lua_close(L);
  return 0;
}

test3.c の実行結果は:

[wtopia lua.hajime]$ ./test3
7
70
1
10
100

関数を一度に登録するには, 以下のように, 関数テーブルを定義しておいて, luaL_openlib() 関数で登録する:

/* 自作関数のライブラリの関数テーブルを定義 */
static const luaL_Reg MyLibTable[] = {
  {"c_add", c_add},
  {"c_sub", c_sub},
  {NULL, NULL}
};

int main(int argc, char *argv[]){
  ...
  // Lua に関数群を登録する
  luaL_openlib(L, "MyLib", MyLibTable, 0);
  ...
}

変数の値の読み書き

次に, 変数の値を読み書きしてみる. 変数の値の読み書きにも, スタックを利用する.

変数の取得

まずは, 変数の取得方法から見ていく. まずは, 値をていする Lua スクリプトである

func4.lua

1
2
3
-- func4.lua
account = "feifei"
password = "hogehoge"

そして, 以下のソースはスクリプトからグローバル変数を取得して表示する

test4.c

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/*
  test4.c
*/
#include <stdio.h>

#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>

/* メイン関数 */
int main(int argc, char *argv[]){
  lua_State *L = luaL_newstate();
  luaL_openlibs(L); // Lua のライブラリを使えるようにする

  // Lua のスクリプトを読み込む
  if( luaL_loadfile(L, "func4.lua") || lua_pcall(L, 0, 0, 0) ){
    printf("func4.lua が読めなかった.\n");
    return -1;
  }

  // グローバル変数の値をスタックに積む
  lua_getglobal(L, "account"); // スタックに積む
  const char *account = lua_tostring(L, -1); // スタックから値を読む
  lua_pop(L, 1); // スタックから値を取り除く

  lua_getglobal(L, "password");
  const char *password = lua_tostring(L, -1);
  lua_pop(L, 1);

  printf("account = %s, password = %s\n", account, password);

  // 閉じる
  lua_close(L);
  return 0;
}

test4.c の実行結果は:

[wtopia lua.hajime]$ ./test4
account = feifei, password = hogehoge

これを見てみると, 変数の値を取得するために, 変数の値をスタックに積みスタックから値を取り出すという手順を踏むことがわかる.

変数に値を設定する

そして, 変数に値をセットする方法だが, こちらもスタックに値を積んでから値を設定する.

まずは, Lua スクリプトから, これは, C 言語側で設定された変数の値を画面に表示するというもの.

func5.lua

1
2
-- func5.lua
print(account)

次に, C 言語側のソースである. スタックに値を追加しておいて, lua_setglobal() を利用してスタックの値を変数に代入する.

test5.c

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/*
  test5.c
*/
#include <stdio.h>

#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>

/* メイン関数 */
int main(int argc, char *argv[]){
  lua_State *L = luaL_newstate();
  luaL_openlibs(L); // Lua のライブラリを使えるようにする
  
  // 変数に値を設定する
  lua_pushstring(L, "feifei");
  lua_setglobal(L, "account");

  // Lua のスクリプトを読み込む
  if( luaL_loadfile(L, "func5.lua") || lua_pcall(L, 0, 0, 0) ){
    printf("func5.luaが読めなかった\n");
    return -1;
  }

  // 閉じる
  lua_close(L);
  return 0;
}

test5.c の実行結果は:

[wtopia lua.hajime]$ ./test5
feifei