UserDataのLuaとCの相互作用(4)



Lua C Interaction Userdata



基本型または拡張型の構造のホストであるかどうかにかかわらず、ホスト型の言語を使用できるluaスクリプトとして、UserDataLuaは拡張のニーズを満たすために提供されました。 Luaはホスト言語タイプで使用され、少なくともいくつかの側面を考慮に入れています。

  1. データメモリ
  2. ライフサイクル
  3. データ操作
    以下では、主に「Luaプログラミング」を参照して、Luaスタックに格納されているデータは、データMetaTable、Gcで動作し、メモリのLuaによって復元されます。

1完全なUserData

void *lua_newuserdata (lua_State *L, size_t size)

この関数は、指定されたサイズの新しいメモリブロックを割り当て、ブロックアドレスを持つ新しい完全なユーザーデータをスタックにプッシュし、このアドレスを返します。ユーザーデータは、LuaのC値を表します。完全なユーザーデータは、メモリのブロックを表します。これは(テーブルのような)オブジェクトです。作成する必要があり、独自のメタテーブルを持つことができ、いつ収集されているかを検出できます。完全なユーザーデータはそれ自体とのみ等しくなります(生の同等性の下で)。Luaがgcメタメソッドを使用して完全なユーザーデータを収集すると、Luaはメタメソッドを呼び出し、ユーザーデータをファイナライズ済みとしてマークします。このユーザーデータが再度収集されると、Luaは対応するメモリを解放します。



関数は、指定されたサイズのメモリ、スタック上の対応するユーザーデータを割り当て、メモリブロックのアドレスを返します。ユーザーデータは独自のメタテーブルを持つことができます。__Gcメタテーブル要素メソッドがある場合、そのメソッドが呼び出されてリカバリが変更されます。回復後、Luaは対応するメモリを解放します。

void *lua_touserdata (lua_State *L, int index)

指定された許容可能なインデックスの値が完全なユーザーデータである場合、そのブロックアドレスを返します。値が軽いuserdataの場合、そのポインタを返します。それ以外の場合は、NULLを返します。



操作例
// structure definition typedef struct NumArray { int size double values[1] /* variable part */ } NumArray // Create an array static int newarray (lua_State *L) { int n = luaL_checkint (L, 1) // check integer size_t nbytes = sizeof(NumArray) + (n - 1)*sizeof(double) NumArray *a = (NumArray *)lua_newuserdata(L, nbytes) a->size = n return 1 /* new userdatum is already on the stack */ } // set values ​​array set (a, index, value) static int setarray (lua_State *L) { NumArray *a = (NumArray *)lua_touserdata(L, 1) int index = luaL_checkint(L, 2) double value = luaL_checknumber(L, 3) luaL_argcheck(L, a != NULL, 1, '`array' expected') luaL_argcheck(L, 1 <= index && index size, 2, 'index out of range') a->values[index-1] = value return 0 } // Get the array elements get (a, index) static int getarray (lua_State *L) { NumArray *a = (NumArray *)lua_touserdata(L, 1) int index = luaL_checkint(L, 2) luaL_argcheck(L, a != NULL, 1, ''array' expected') luaL_argcheck(L, 1 <= index && index size, 2,'index out of range') lua_pushnumber(L, a->values[index-1]) return 1 } // library definition static const struct luaL_reg arraylib [] = { {'new', newarray},{'set', setarray},{'get', getarray},{NULL, NULL} } int luaopen_array (lua_State *L) { luaL_openlib(L, 'array', arraylib, 0) return 1 }

ライブラリの上にインポートすると、Luaで配列を操作できます。

a = array.new (1000) - Creating array.set (a, 1, 10) - Set print (array.get (a, 10)) - Get

2 MetaTable

異なるタイプのCuserDataを区別するために、異なるメタテーブルuserDataに追加される場合があります。私たちが訪問するたびに、彼が正しいメタテーブルを持っているかどうかを確認する必要があります。 Luaコードはメタテーブルuserdatumを変更できないため、彼は私たちのコードを偽造しません。

操作機能
int luaL_newmetatable (lua_State *L, const char *tname)

新しいテーブル(メタテーブルとして使用される)を作成し、新しいテーブルをスタックの一番上に作成し、連絡先の名前でテーブルとレジストリタイプを設定します



void luaL_getmetatable (lua_State *L, const char *tname)

Tnameは、対応するメタテーブルレジストリをスタックに取得します

void *luaL_checkudata (lua_State *L, int index, const char *tname)

スタック内のオブジェクトで指定された場所が、指定された名前userdataでメタテーブルであるかどうかを確認します。オブジェクトがそうでない場合
正しいメタテーブルが含まれ、NULLを返します。それ以外の場合は、リターンアドレスuserdataを返します。

ケースの変更
// First create the meta table named LuaBook.array int luaopen_array (lua_State *L) { luaL_newmetatable(L, 'LuaBook.array') ... } When // Create an array, add metadata table method Userdata static int newarray (lua_State *L) { ... luaL_getmetatable(L, 'LuaBook.array') lua_setmetatable(L, -2) ... } // add detection metatable name is correct interface static NumArray *checkarray (lua_State *L) { void *ud = luaL_checkudata(L, 1, 'LuaBook.array') luaL_argcheck(L, ud != NULL, 1, '`array' expected') return (NumArray *)ud }

これにより、関連するタイプのメタテーブルが作成され、メタテーブルを設定するときにUserDataが作成されます。最初に取得すると、メタがオンかどうかが検出されます。

3オブジェクト指向アクセス

これは、オブジェクト指向マナーモードのオブジェクトへのCメタテーブルアクセスで要素メソッドuserdataを拡散することによって実現できます。

Cで定義されている
// Metatable increase __index, __newindex method int luaopen_array (lua_State *L) { luaL_newmetatable(L, 'LuaBook.array') lua_pushstring(L, '__index') lua_pushvalue(L, -2) /* pushes the metatable */ lua_settable(L, -3) /* metatable.__index = metatable */ // first call, when we pass a NULL as the library name, luaL_openlib did not create any table that contains the function the contrary, he believed table wrapper function within the stack, located under the temporary upvalues luaL_openlib(L, NULL, arraylib_m, 0) // create a new table based on a given array name, and register specified in the table function luaL_openlib(L, 'array', arraylib_f, 0) return 0 } // define Userdata Methods static const struct luaL_reg arraylib_f [] = { {'new', newarray}, {NULL, NULL} } Metatable method // defined static const struct luaL_reg arraylib_m [] = { {'set', setarray},{'get', getarray},{NULL, NULL} }

オブジェクト構造は、拡張要素メソッドMetatableLuaの便利なアクセスによって実現されます。
luaL_openlib(L、NULL、arraylib_m、0)は、メタテーブルarraylib_mのメソッドに追加する必要があります。実際、設定可能な方法で設定できる場合があります。インジェクションメソッドをメタテーブルに取得します。

Luaの定義

または、 Luaユーザーデータはメタテーブルを提供しました 、ただし、インポートするには配列ライブラリの後に実行する必要があります。

function RegsterMetatable(a) local metaarray = getmetatable(a) metaarray.__index = metaarray metaarray.set = array.set metaarray.get = array.get metaarray.size = array.size end

3完全なUserdataライフサイクルの場合

上記で定義された操作フローは、Luaメモリ内のlua_newuserdataによって作成され、アドレスをCに返します。Cはメモリ操作のメソッドを提供します。 LuaはMetatableUserDataによるアクセスを容易にします。ただし、ポインターをC lua_newuserdata returnに保存し、Luaの後に解放すると、ポインターに格納されているCは失敗します。ライフサイクルに関するUserDataの質問は、以下を参照できます。 ユン・フェンの記事

4.軽いUserData

軽いユーザーデータポインタ値Cは表現です(つまり、タイプvoid *の値)。関数lua_pushlightuserdataを使用してそれらを作成できない値であるため、ライトユーザーデータスタック:

void lua_pushlightuserdata (lua_State *L, void *p)

ライトユーザーデータはバッファゾーンではなく、単なるポインタであり、メタテーブルではありません。同様に、デジタルのように、軽いユーザーデータガベージコレクターは彼女を管理する必要はありません。一部の人々は、完全なユーザーデータではなく、代替の低コストの実装としてユーザーデータを軽量化しますが、これは軽量ユーザーデータの典型的なアプリケーションではありません。まず、メモリを管理する必要がある軽いユーザーデータです。これらはガベージコレクタとは無関係であるためです。第二に、名前から判断するとストレスがありますが、完全なユーザーデータのコストは大きくないことも認識しています。比較的言えば、彼は割り当てられたメモリの量だけであり、少し余分なコストがありました。
軽いユーザーデータの実際の使用は、さまざまなタイプのオブジェクトを表す場合があります。一方、完全なuserdataがオブジェクトであり、それがオブジェクト自体と等しい場合、軽いuserdataはオブジェクトへのポインターによって表されます。同じように、それは任意のタイプのポインターuserdataと等しくなります。そのため、LuaのCオブジェクトを表すlightuserdataを使用します。

Yun Fengのブログにあるいくつかのシナリオ:
[Lua拡張機能Cでの記述に使用されるいくつかの手法] [ http://blog.codingnow.com/2006/11/lua_c.html ]
[仮想マシンluaに情報を伝達する] [ http://blog.codingnow.com/2006/01/_lua.html ]
[完全なユーザーデータの要素を削除するGCメソッド] [ http://blog.codingnow.com/2013/08/full_userdata_gc.html ]

結論

本を書くのに時間をかけたくなかったのですが、常にウルアを達成するために、その中のさまざまなユーザーデータの使用が完全に理解していることを理解し、それらはまだ真剣に要約するようになります。もちろん、真ん中は他の多くの主題も行います、後者はさらにそのアプリケーションを紹介します。

補足:

Lua5.1は__gc要素メソッドを使用したユーザーデータをサポートします。Lua5.2も共通テーブルをサポートした後、Apiインタラクションをより便利な時間に設定します。詳細については、以下を参照してください。
[ファイナライザーのLuaGC] [ http://www.cnblogs.com/JesseFang/archive/2012/12/27/2836160.html ]