LuaとC言語のインタラクション(三)

20974 ワード

カスタムデータ型:
C言語を用いてLua配列を実装することによって,Luaがカスタムユーザデータを実装することを実証した.配列の構造は以下の通りです.
typedef struct NumArray{
int size; //
double values[]; // values double* ,values NumArray
} NumArray;
配列の新規作成、読み取り、書き込み、サイズの取得に使用される4つの関数new、get、set、sizeを実装します.Luaでカスタムデータ構造を実現するために使用されるタイプをuserdataと呼ぶ.Luaはuserdataを作成するためのインタフェースを提供しています:void*lua_新userdata(lua_State*L,size_t size)は、sizeサイズのメモリをuserdataとして割り当ててスタックに押し込み、関数の戻り値は新しく確立されたuserdataであり、必要なデータ構造に自由に変換できる.カスタムデータ構造を実現するCコードは以下の通りである:
/* array */
static int newarray (lua_State *L){
int n = luaL_checkint(L, -1); // ,
size_t nbytes = sizeof(NumArray) + n*sizeof(double); // C ,nbytes
NumArray *a = (NumArray *)lua_newuserdata(L, nbytes); // nbytes userdata 。
a->size = n; // NumArray
return 1;
}
/* array */
static int setarray(lua_State *L) {
NumArray *a = (NumArray *)lua_touserdata(L, -3); // userdata
int index = luaL_checkint(L, -2); //
double value = luaL_checknumber(L, -1); //

luaL_argcheck(L, NULL != a, 1, "'array' expected"); // , ,
luaL_argcheck(L, index >= 0 && index <= a->size, 1, "index out of range");

a->values[index - 1] = value; // lua C

return 0;
}

/* array */
static int getarray(lua_State *L) {
NumArray *a = (NumArray *)lua_touserdata(L, -2); // setarray
int index = luaL_checkint(L, -1);

luaL_argcheck(L, NULL != a, 1, "'array' expected");
luaL_argcheck(L, index >= 1 && index <= a->size, 1, "index out of range");
lua_pushnumber(L, a->values[index - 1]); // C

return 1;
}

/* array */
static int getsize(lua_State *L) {
NumArray *a = (NumArray *)lua_touserdata(L, -1);
luaL_argcheck(L, NULL != a, 1, "'array' expected");

lua_pushnumber(L, a->size);

return 1;
}

/* , luaL_openlib lua */
static const struct luaL_Reg arraylib[] = {
{"new", newarray},
{"set", setarray},
{"get", getarray},
{"size", getsize},
{NULL, NULL}
};

int main(int argc, char* argv[])
{
......
luaL_openlib(L, "array", arraylib, 0); // array , new,set,get size。
......
return 0;
}

するLuaプログラムは:
a = array.new(1000)
print(a)
print(array.size(a))
for i=1,999 do
array.set(a, i, 1/i)
end

print ("Print first 10 elements")
for i=1,10 do
print(array.get(a, i) )
end

は:
pi@raspberrypi ~/Programming/article_lua $ ./a.out userdata3.lua
userdata: 0x20237b0
1000
Print first 10 elements
1
0.5
0.33333333333333
0.25
0.2
0.16666666666667
0.14285714285714
0.125
0.11111111111111
0.1
ですが、 のプログラムでは2つの があります:1、パラメータの でユーザーの パラメータがuserdataであるかどうかを しただけで、 のタイプを していません.get(io.stdin,200)は、Sagement faultをもたらすという は け れられない.2、ユーザーはarrayのみ できる.size(a)、array.get(a,40)の でコンテンツにアクセスし、a:size()やa:get(40)のようなオブジェクト けの に た を できますか? えは であるためmetatableのメカニズムを しなければならない. はlua そのものとLuaでmetatableを することについて の を っていると し,ここではC でuserdataにmetatableを する についてのみ する.userdataのmetatableには、1、metatableはluaでは のtableであるが、luaがC に するインタフェースでは、metabtableは のインタフェースを して および み りする があることに してください.( はしばらく )2、luaのmetatableとjavascriptのprototypeは います.オブジェクトが しているメソッドにアクセスするとjavascriptはprototypeが すオブジェクトから しているメソッドを しますが、luaとは なり、metatableから するのではなく、metatableの__から します.indexドメインが すオブジェクトで します.objectを するとmetatable.__index = object.metatable、これでjavascriptと ています.オブジェクトが しているメソッドはmetatableから されます.3、userdataには の もないので、 のメンバーへのアクセスはmetatable._indexによって されます(metatable._index=metatableが されている 、userdataにアクセスするメンバーはuserdataにアクセスするmetatableに します).
metatableで したプログラムは の りです:
/*
arraylib_f array
arraylib_m metatable, methord
*/
static const struct luaL_Reg arraylib_f[] = {
{"new", newarray},
{NULL, NULL}
};
static const struct luaL_Reg arraylib_m[] = {
{"set", setarray},
{"get", getarray},
{"size", getsize},
{NULL, NULL}
};

/* C
metatable, metatable metatable
*/
static void install_func(lua_State *L)
{
luaL_newmetatable(L, "LuaBook.array"); // metatable, , metatable "LuaBook.array" key register (register )

lua_pushstring(L, "__index");
lua_pushvalue(L, -2);
lua_settable(L, -3); // metatable __index , metatable.__index = metatable, , table2, metatable.__index = table2
luaL_openlib(L, NULL, arraylib_m, 0); // set、get、size metatable( luaL_openlib NULL , )

luaL_openlib(L, "array", arraylib_f, 0); // new array
}

static int newarray (lua_State *L){
int n = luaL_checkint(L, 1);
size_t nbytes = sizeof(NumArray) + n*sizeof(double);
NumArray *a = (NumArray *)lua_newuserdata(L, nbytes);

luaL_getmetatable(L, "LuaBook.array");
lua_setmetatable(L, -2); // userdata register LuaBook.array metatable array , array metatable
a->size = n;
return 1;
}

static int setarray(lua_State *L) {
NumArray *a = (NumArray *)luaL_checkudata(L, -3, "LuaBook.array"); // , userdata , userdata metatable "LuaBook.array", io.stdin , Sagement fault
int index = luaL_checkint(L, -2);
double value = luaL_checknumber(L, -1);

luaL_argcheck(L, NULL != a, 1, "'array' expected");
luaL_argcheck(L, index >= 0 && index <= a->size, 1, "index out of range");

a->values[index - 1] = value;

return 0;
}

static int getarray(lua_State *L) {
NumArray *a = (NumArray *)luaL_checkudata(L, -2, "LuaBook.array"); // metatable
int index = luaL_checkint(L, -1);

luaL_argcheck(L, NULL != a, 1, "'array' expected");
luaL_argcheck(L, index >= 0 && index <= a->size, 1, "index out of range");

lua_pushnumber(L, a->values[index - 1]);

return 1;
}

static int getsize(lua_State *L) {
NumArray *a = (NumArray *)luaL_checkudata(L, -1, "LuaBook.array"); // metatable

luaL_argcheck(L, NULL != a, 1, "'array' expected");
lua_pushnumber(L, a->size);

return 1;
}

int main(int argc, char* argv[])
{
......
install_func(L); // install_func lua
......
}

するLuaの は、
a = array.new(1000)
print(a)
print(a:size())
for i=1,999 do
a:set(i, 1/i)
end
となる

print ("Print first 10 elements")
for i=1,10 do
print(a:get(i))
end

この で するサンプル・プログラム:
にmain の を します.この では、 したサンプルコードを して、 なサンプルプログラムを み わせることができます.
int main(int argc, char* argv[])
{
char* filename;
double ret = 0;
// lua state
lua_State *L = luaL_newstate();

if (argc >=2 ){
filename = argv[1];
} else {
printf("usage: %s filename
", argv[0]);
return 1;
}

// lua
luaL_openlibs(L);

/* C */

/* lua ( chunk ) */
if (luaL_loadfile(L, filename)){
error(L, "cannot run file: %s", lua_tostring(L, -1));
}

/* lua */
if (lua_pcall(L, 0, 0, 0)){
error(L, "cannot run file: %s", lua_tostring(L, -1));
}
/* lua , */

return 0;
}
に きます: は がLuaの な に してすでに の を っていると します.Luaはプロトタイプ なので、 たちが っていたタイプベースの とは し います(Javascriptと ていますが、Javascriptもプロトタイプ です).そのため、 を める で ず と の から び してこそ、Luaを に することができる. に2つの Luaの な を します: マニュアル:http://www.lua.org/manual/ べやすいので、それを って するのは しいです. の :Programming in Lua, 1 Lua 5.0http://www.lua.org/pil/contents.htmlああ、ネット で のバージョンを することができて、 は が だと じて、もちろんamazonで の 3 を うことができます.