C調Lua

10390 ワード

変換元:http://foredoomed.org/blog/2013/12/07/integrate-c-with-lua/
 
我々はCでプログラムを書く場合,リスト,Mapなどの集合を用いることが多いが,Cはこれらのデータ構造を原生的にサポートしていない.このような場合、自分でAPIを実現するか、他人が書いた既存のクラスライブラリを使うかのどちらかです.しかし、多くの場合、既存のクラスライブラリのAPIは使い心地が悪く、自分で書いたり車輪を繰り返したりしていますが、他の方法はありませんか?答えは肯定的だ.Luaという埋め込みスクリプト言語をCと組み合わせて使用することで、Cという古い言語の多くの先天的な不足を補うことができます.
0.Luaとは
Luaの公式サイトの説明を引用します.
Lua is a powerful, fast, lightweight, embeddable scripting language.
Lua combines simple procedural syntax with powerful data description constructs based on associative arrays and extensible semantics. Lua is dynamically typed, runs by interpreting bytecode for a register-based virtual machine, and has automatic memory management with incremental garbage collection, making it ideal for configuration, scripting, and rapid prototyping.
LuaとRuby、Pythonは同じスクリプト言語ですが、Luaには他のスクリプト言語にはない特性があります.Luaは埋め込みスクリプト言語です.Luaスクリプトは、C/C++コードによって容易に呼び出されてもよいし、C/C++の関数を逆に呼び出すこともでき、アプリケーションにおいてLuaを広く応用することができる.Luaは標準Cで作成され、コードは簡潔で優美で、ほとんどのオペレーティングシステムとプラットフォームでコンパイルし、実行することができます.完全なLua解釈器は200 kにすぎず、現在のすべてのスクリプトエンジンの中でLuaの速度が最も速い.
また、LuaにはLuaJITのプロジェクトがあり、特定のプラットフォームでのインスタントコンパイル機能を提供することができ、Luaにより優れた性能をもたらすことができます.
1.CでLuaスクリプトを実行する
まずCコード:
#include "lua.h" #include "lauxlib.h" #include "lualib.h" int main(){ lua_State *L = luaL_newstate(); /* opens Lua */ luaL_openlibs(L); /* opens the standard libraries */ luaL_dofile(L,"test.lua"); /* runs Lua script */ lua_close(L); return 0; }

そしてLuaスクリプト:
print("This is executed from C")

最終コンパイル実行:
$ gcc -o test test.c -I/usr/local/Cellar/lua/5.1.5/include -llua $ ./test This is executed from C

このコードを詳しく見てみましょう.まず、3つのヘッダファイルlua.hlauxlib.hlualib.hを導入します.lua.hで定義されているのは最も基礎的なAPIであり、lauxlib.hの関数はすべてluaL_で始まり、彼らは基礎的なAPIよりも抽象的な関数であり、lualib.hではluaL_openlibs(L)のような標準クラスライブラリを開くAPIが定義されている.
プログラムはluaL_newstate()関数でlua_Stateを作成し始めた.lua_StateにはLua実行時のすべての状態情報(例えば変数の値など)が保存され、すべてのLuaのCのAPIにはlua_newstateポインタのパラメータがある.luaL_newstate関数は、事前に定義された関数(最も基本的なprint関数を含む)がない新しいLuaランタイム状態を作成します.標準クラスライブラリを試用する必要がある場合は、luaL_openlibs(L)関数を呼び出すだけで標準クラスライブラリを開くことができます.標準クラスライブラリはそれぞれ異なるパッケージにカプセル化されており、使用する必要があるときにコードに導入すると、Luaをできるだけ小さく(埋め込み言語は小さくしなければならない)することができ、他の言語に簡単に埋め込むことができます.Lua実行時の状態と標準クラスライブラリの準備が完了すると、luaL_dofile(L,"test.lua")関数を呼び出してLuaスクリプトを実行できます.運転終了後、Lua運転時状態を閉じるためにlua_close(L)を呼び出す必要がある.
2.LuaとCのデータ交換
CでLuaのAPIを呼び出すと(例えば、変数をLuaのデータ構造に保存する)、LuaはCのデータを読み出して保存する必要がある.しかし、問題はCとLuaが2つの異なる言語であることです.前者は静的で、メモリを手動で管理する言語です.後者はダイナミックで、メモリを自動的に管理する言語なので、Luaは実行時に自分のstackを維持してCとデータ交換をします.このstackの各スロットは任意のLuaタイプであってもよく、Luaから値を要求してLuaのAPIを呼び出す必要がある場合、この値はpushによってstackに呼び出されます.Luaに値を伝えたい場合は、まずこの値をstackにpushしてからLuaのAPIを呼び出さなければなりません.デフォルトではLuaのstackは20スロットで使用でき、いつでもpush値からstackまでstackに空き領域があることを保証しなければならないので、プログラムがstackをオーバーフローさせる可能性がある場合はlua_checkstack関数を呼び出してstackの空間に空き領域があるかどうかを確認する必要があります.
3.CでLuaのtableを使う
Luaのtableはとても使いやすいデータ構造で、JavaのMapに少し似ています.
Cコード:
#include <stdio.h> #include "lua.h" #include "lauxlib.h" #include "lualib.h" int main(){ lua_State *L = luaL_newstate(); /* opens Lua */ luaL_openlibs(L); /* opens the standard libraries */ lua_newtable(L); /* creates a new table */ lua_pushstring(L, "test"); lua_pushstring(L, "Hello World"); lua_settable(L, -3); /* t["test"] = "Hello World" */ lua_pushstring(L, "test"); lua_gettable(L, -2); /* pushes t["test"] onto the stack top */ const char *str = lua_tostring(L, -1); printf("%s", str); lua_close(L); return 0; }

コンパイル実行:
$ gcc -o test test.c -I/usr/local/Cellar/lua/5.1.5/include -llua $ ./test Hello World

CでLuaのtableを試用するのはとても簡単で、最も主要なのはstackに対するpopとpush操作です.上記のコードは、まず空のtableを作成し、stackにpushを作成し、次に2つのグリッド文字列(keyとして、valueとして)stackにpushを作成します.なお、Luaの下付き文字は1から始まるので、lua_settable関数を呼び出すとtableのindex値は-3(上から下へ数えるindexは負数)になります.lua_settable関数呼び出しが完了するとpopはkeyとvalueを削除します.そうするとstackはtableしか残っていません.tableの値を取るにはpushでkey値を1回押さなければなりません.そうすれば、対応するvalue値を取ることができます.
4.まとめ
現在、LuaはクラスC言語(C/C++/objective C)と協力して開発されることが多く、Luaが小さく、速度が速く、動的言語の特性を重視している.Luaを使用すると、アプリケーションに柔軟な拡張機能とカスタマイズ機能を提供し、アプリケーションの拡張性を大幅に向上させることができます.
リファレンスドキュメント
[1]  Lua 5.1 Reference Manual