Luaチュートリアル(XIX)。C言語からLuaへの呼び出し
1. 基本的なこと
Luaの重要な用途として、設定言語としての利用が挙げられます。まずは簡単な例から見ていきましょう。
-- Here is the configuration information for the window size defined in Lua code
width = 200
height = 300
以下は、設定情報を読み込むためのC/C++のコードです。
#include <stdio.h>
#include <string.h>
#include <lua.hpp>
#include <luxlib.h>
#include <lualib.h>
void load(lua_State* L, const char* fname, int* w, int* h) {
if (luaL_loadfile(L,fname) || lua_pcall(L,0,0,0)) {
printf("Error Msg is %s.\n",lua_tostring(L,-1));
return;
}
lua_getglobal(L,"width");
lua_getglobal(L,"height");
if (!lua_isnumber(L,-2)) {
printf("'width' should be a number\n" );
return;
}
if (!lua_isnumber(L,-1)) {
printf("'height' should be a number\n" );
return;
}
*w = lua_tointeger(L,-2);
*h = lua_tointeger(L,-1);
}
int main()
{
lua_State* L = luaL_newstate();
int w,h;
load(L,"D:/test.lua",&w,&h);
printf("width = %d, height = %d\n",w,h);
lua_close(L);
return 0;
}
以下は、新機能の説明です。
lua_getglobalは、プロトタイプがマクロである。#define lua_getglobal(L,s) lua_getfield(L, LUA_GLOBALSINDEX, (s))です。
このマクロは、呼び出されるたびに、Luaコード内の対応するグローバル変数の値をスタックに押し出します。最初に呼び出されたときは、グローバル変数 "width" の値をスタックに押し出し、再度呼び出されたときは "height" の値をスタックに押し出します。
2.テーブルの操作。
C言語のコード内からLuaのテーブルデータを操作できるのは、非常に便利で有用な機能です。Luaコードの構造が明確になるだけでなく、Cコードで同等の構造を定義することで、可読性が格段に向上します。以下のコードを見てください。
#include <stdio.h>
#include <string.h>
#include <lua.hpp>
#include <luxlib.h>
#include <lualib.h>
void load(lua_State* L) {
if (luaL_loadstring(L,"background = { r = 0.30, g = 0.10, b = 0 }")
|| lua_pcall(L,0,0,0)) {
printf("Error Msg is %s.\n",lua_tostring(L,-1));
return;
}
lua_getglobal(L,"background");
if (!lua_istable(L,-1)) {
printf("'background' is not a table.\n" );
return;
}
lua_getfield(L,-1,"r");
if (!lua_isnumber(L,-1)) {
printf("Invalid component in background color.\n");
return;
}
int r = (int)(lua_tonumber(L,-1) * 255);
lua_pop(L,1);
lua_getfield(L,-1,"g");
if (!lua_isnumber(L,-1)) {
printf("Invalid component in background color.\n");
return;
}
int g = (int)(lua_tonumber(L,-1) * 255);
lua_pop(L,1);
lua_pushnumber(L,0.4);
lua_setfield(L,-2,"b");
lua_getfield(L,-1,"b");
if (!lua_isnumber(L,-1)) {
printf("Invalid component in background color.\n");
return;
}
int b = (int)(lua_tonumber(L,-1) * 255);
printf("r = %d, g = %d, b = %d\n",r,g,b);
lua_pop(L,1);
lua_pop(L,1);
return;
}
int main()
{
lua_State* L = luaL_newstate();
load(L);
lua_close(L);
return 0;
}
void lua_getfield(lua_State *L, int idx, const char *k); 第2引数はスタック上のテーブル変数のインデックス値、最後の引数はテーブルのキー値です。この関数は正常に実行されると、フィールド値をスタックに押下します。
void lua_setfield(lua_State *L, int idx, const char *k); 第2引数はスタック上のテーブル変数のインデックス値、最後の引数はテーブルのキー名、フィールド値は前のコマンド lua_pushnumber(L,0.4) でスタック上に押し込まれており、関数が成功すると今押し込んだフィールド値をスタックからポップするようになります。
次のコード例では、Cコードでテーブル・オブジェクトを構築しながら、テーブルのフィールド値を初期化し、最後にLuaのグローバル変数にテーブル・オブジェクトを代入しています。
#include <stdio.h>
#include <string.h>
#include <lua.hpp>
#include <luxlib.h>
#include <lualib.h>
void load(lua_State* L)
{
lua_newtable(L);
lua_pushnumber(L,0.3);
lua_setfield(L,-2,"r");
lua_pushnumber(L,0.1);
lua_setfield(L,-2,"g");
lua_pushnumber(L,0.4);
lua_setfield(L,-2,"b");
lua_setglobal(L,"background");
lua_getglobal(L,"background");
if (!lua_istable(L,-1)) {
printf("'background' is not a table.\n" );
return;
}
lua_getfield(L,-1,"r");
if (!lua_isnumber(L,-1)) {
printf("Invalid component in background color.\n");
return;
}
int r = (int)(lua_tonumber(L,-1) * 255);
lua_pop(L,1);
lua_getfield(L,-1,"g");
if (!lua_isnumber(L,-1)) {
printf("Invalid component in background color.\n");
return;
}
int g = (int)(lua_tonumber(L,-1) * 255);
lua_pop(L,1);
lua_getfield(L,-1,"b");
if (!lua_isnumber(L,-1)) {
printf("Invalid component in background color.\n");
return;
}
int b = (int)(lua_tonumber(L,-1) * 255);
printf("r = %d, g = %d, b = %d\n",r,g,b);
lua_pop(L,1);
lua_pop(L,1);
return;
}
int main()
{
lua_State* L = luaL_newstate();
load(L);
lua_close(L);
return 0;
}
上記のコードでは、先ほどのコードと同じ結果が出力されます。
lua_newtableはマクロで、プロトタイプは以下の通りです。#define lua_newtable(L) lua_createtable(L, 0, 0)です。このマクロが呼ばれると、Luaは新しいテーブル・オブジェクトを生成し、スタックに押し付けます。
lua_setglobal は、プロトタイプがマクロです。#define lua_setglobal(L,s) lua_setfield(L,LUA_GLOBALSINDEX,(s)) です。このマクロを呼び出すと、Luaは第2引数で指定されたグローバル変数名に、現在のスタックの先頭の値を代入する。このマクロが正常に実行されると、割り当てられたばかりの値がスタックの先頭からポップアップします。
3. Luaの関数を呼び出す。
関数を呼び出すためのAPIも非常にシンプルです。まず呼び出す関数をスタックに押し出し、次に関数の引数を押し、次にlua_pcallを使って実際に呼び出し、最後に呼び出しの結果をスタックからポップさせます。次のコードを見てください。
#include <stdio.h>
#include <string.h>
#include <lua.hpp>
#include <luxlib.h>
#include <lualib.h>
const char* lua_function_code = "function add(x,y) return x + y end";
void call_function(lua_State* L)
{
//luaL_dostring is equivalent to luaL_loadstring() || lua_pcall()
//Note: you must execute the Lua script before you can call the Lua function, otherwise you will get an error when you actually call the Lua function later.
//The error message is: "attempt to call a nil value."
if (luaL_dostring(L,lua_function_code)) {
printf("Failed to run lua code.\n");
return;
}
double x = 1.0, y = 2.3;
lua_getglobal(L,"add");
lua_pushnumber(L,x);
lua_pushnumber(L,y);
// The second argument below indicates the presence of two arguments to the lua function with the call.
//The third argument means that even if the function with the call has multiple return values, then only one will be pressed onto the stack after execution.
//After the lua_pcall call, the function arguments and function names are popped out of the virtual stack.
if (lua_pcall(L,2,1,0)) {
printf("error is %s.\n",lua_tostring(L,-1));
return;
}
//At this point the result has been pressed onto the stack.
if (!lua_isnumber(L,-1)) {
printf("function 'add' must return a number.\n");
return;
}
double ret = lua_tonumber(L,-1);
lua_pop(L,-1); //pop the return value.
printf("The result of call function is %f.\n",ret);
}
int main()
{
lua_State* L = luaL_newstate();
call_function(L);
lua_close(L);
return 0;
}
関連
-
Luaのプログラミング例(4)。テーブルライブラリ、文字列ライブラリ、システムライブラリからなるLua標準ライブラリ
-
Luaで式を解析するためのディープダイブ
-
LuaアプリケーションでSQLiteを使用するためのチュートリアル
-
Luaにおけるif文の使い方を説明します。
-
Luaで関係演算子を使用するためのチュートリアル
-
フォルダの再帰的削除のためのLuaスクリプト
-
Luaは配列(tabble)に値が含まれているかどうかを検出します。
-
Luaのアサインメントタイプコードの説明
-
Luaチュートリアル(6):コンパイルと実行でエラーが発生した場合
-
Luaチュートリアル(V)。イテレータとジェネリック・フォー
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン