Luaチュートリアル(20)。LuaがCの関数を呼び出す
LuaがC言語の関数を呼び出せるようになると、Luaのスケーラビリティや使い勝手が大きく向上します。OSに関連する一部の機能や、高い効率が求められるモジュールについては、C関数で実装し、Luaから指定されたC関数を呼び出すことが可能です。Luaから呼び出せるC関数については、Luaが要求する形式、すなわちtypedef int (*lua_CFunction)(lua_State* L)に沿ったインタフェースが必要です。簡単に説明すると、この関数型はLua環境へのポインタを唯一の引数として持ち、実装者はこれを通じてLuaコードで渡された実際の引数にアクセスすることができます。戻り値は整数で、C関数がLuaコードに返す戻り値の数を表し、戻り値がない場合は0を返します。ここで重要なのは、C関数は実際の戻り値を直接Luaコードに返すのではなく、LuaコードとC関数の間で仮想スタックを介して呼び出しパラメータと戻り値を受け渡しする点です。ここでは、LuaでC関数を呼び出す際の2つのルールについて説明します。
1. アプリケーションの一部としてのC関数
#include <stdio.h>
#include <string.h>
#include <lua.hpp>
#include <luxlib.h>
#include <lualib.h>
// C registered functions to be called by Lua.
static int add2(lua_State* L)
{
// Check that the arguments in the stack are legal. 1 means the first argument (from left to right) when Lua is called, and so on.
//If the Lua code passes an argument that is not number when called, the function will report an error and terminate the execution of the program.
double op1 = luaL_checknumber(L,1);
double op2 = luaL_checknumber(L,2);
//Press the result of the function onto the stack. If there are multiple return values, they can be pressed onto the stack multiple times here.
lua_pushnumber(L,op1 + op2);
// The return value is used to indicate the number of return values, i.e. the number of return values pressed onto the stack, for this C function.
return 1;
}
// Another C-registered function to be called by Lua.
static int sub2(lua_State* L)
{
double op1 = luaL_checknumber(L,1);
double op2 = luaL_checknumber(L,2);
lua_pushnumber(L,op1 - op2);
return 1;
}
const char* testfunc = "print(add2(1.0,2.0)) print(sub2(20.1,19))";
int main()
{
lua_State* L = luaL_newstate();
luaL_openlibs(L);
//register the specified function as a global function variable in Lua, where the first string argument is the Lua code
//The name of the global function to use when calling the C function, and the second argument is a pointer to the actual C function.
lua_register(L, "add2", add2);
lua_register(L, "sub2", sub2);
// After registering all the C functions, you can use them in Lua code blocks.
if (luaL_dostring(L,testfunc))
printf("Failed to invoke.\n");
lua_close(L);
return 0;
}
2. C言語関数ライブラリがLuaのモジュールになる。
Linuxならso、WindowsならDLLなど、C関数を含むコードのライブラリファイルを生成し、Luaパーサーが正しく位置を特定できるように、Luaコードが置かれているカレントディレクトリ、もしくは環境変数LUA_CPATHが指すディレクトリにコピーすることも行います。現在のWindowsシステムでは、Luaが呼び出せる全てのCライブラリを含む""C:³ Files³ Lua³ 5.1³³clibs³ "にコピーしています。以下のCコードとキーコメントをご覧ください。
#include <stdio.h>
#include <string.h>
#include <lua.hpp>
#include <luxlib.h>
#include <lualib.h>
// The C function to be registered, which is declared in the form given in the example above.
//It should be noted that the function must be exported as C, so extern "C" is required.
//The function code is the same as the above example, so we won't go over it here.
extern "C" int add(lua_State* L)
{
double op1 = luaL_checknumber(L,1);
double op2 = luaL_checknumber(L,2);
lua_pushnumber(L,op1 + op2);
return 1;
}
extern "C" int sub(lua_State* L)
{
double op1 = luaL_checknumber(L,1);
double op2 = luaL_checknumber(L,2);
lua_pushnumber(L,op1 - op2);
return 1;
}
// The first field of the luaL_Reg structure is a string that is used to inform Lua of the name of the function during registration.
//The first field is a pointer to a C function.
//Both fields of the last element of the structure array are NULL, to indicate that the Lua registration function has reached the end of the array.
static luaL_Reg mylibs[] = {
{"add", add},
{"sub", sub},
{NULL, NULL}
};
// The only entry function for this C library. Its function signature is equivalent to the registered function above. See the following points for clarification.
//1. We can understand this function simply as a factory function for the module.
//4. It is important to emphasize that all code that requires the use of "xxx" must be consistent, regardless of C or Lua, as is the Lua convention that
// Otherwise it will not be called.
extern "C" __declspec(dllexport)
int luaopen_mytestlib(lua_State* L)
{
const char* libName = "mytestlib";
luaL_register(L,libName,mylibs);
return 1;
}
以下のLuaのコードをご覧ください。
require "mytestlib" -- specify package name
-- when called, it must be package.function
print(mytestlib.add(1.0,2.0))
print(mytestlib.sub(20.1,19))
関連
最新
-
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 実装 サイバーパンク風ボタン