1. ホーム
  2. スクリプト・コラム
  3. ルア

luaとcの相互作用について簡単に説明します。

2022-01-06 19:33:52

はじめに

luaとcの親密度は仮想スタックに依存しています。luaはこの仮想スタックを使用してcとの間で値を受け渡しします。スタックの各要素はluaの値(nil, number, string...)です。

luaがc関数を呼び出すと、c関数自身のスタックからもlua自身のスタックからも独立した、新しいスタックを取得します。このスタックには、luaがc関数に渡したい全ての引数が格納されています。c関数は次に、返された結果をこのスタックに格納し、呼び出し元に返します。

スタッククエリの操作については、スタックのルールに従えば、スタックの一番上にある要素しか取得できない。しかし、ここでは通常のスタックと異なる点があります。それは、インデックスを使って、スタック上の任意の要素を指し示すことができることです。正の数 (1.. .n) のインデックスは、スタックの下から上へ、1 はスタックの最初の要素、n はスタッ クの一番上の要素を指し、負の数 (-1...-n) はスタックの上から下へ、-1 はスタックの一番上の要素、-n はスタックの一番上の要素 を指します。この 2 つのインデックスの付け方で,スタックの中の要素を簡単に得ることができる.

基本操作

luaとcの橋渡しをするのが仮想スタックで、luaのc apiではlua_Stateと呼ばれています。以下のコードは、スタックを作成し、スタックに要素を追加し、インデックスに従ってスタック内の要素の値を取得するという、lua_Stateの最も基本的な操作を行っているところです。

lua_State *L = luaL_newstate();//create a new stack

lua_pushstring(L, "muzixiaoxin"); //push a string onto the stack
lua_pushnumber(L, 875);//push an integer onto the stack

//now there are two elements on the stack, the bottom of the stack is the string "muzixiaoxin", the top of the stack is the integer 875
//"muzixiaoxin" the index is 1, or -2
//the index of 855 is 2, or -1

if (lua_isstring(L, 1)){//Determine if the element at the bottom of the stack is a string
  printf("%s\n",lua_tostring(L, 1));//If it is a string, convert to string output
}

if (lua_isnumber(L, -1)){//Determine if the element at the top of the stack is of type number
  printf("%d", lua_tonumber(L, 2));//if it's a number, output it as a number
}

lua_close(L); //remember to release when not needed



c コールルア

luaの呼び出しはあまり見たことがなく、通常はlua VMが直接スクリプトを実行しています。cの設定ファイルとしてluaを使用しているものもあります。

例として、新しいluaファイルtest.luaを作成します。

name = "muzixiaoxin"
version = 1003


cはこのファイルをlua c apiを通して読み込み、実行する必要があります。実行結果はスタックにあり、このスタックに移動して変数の値を取得します。

次のCのコードを見てください。

lua_State *L = luaL_newstate();

int err = luaL_loadfile(L, "test.lua"); //load the lua file as a block of code, just load it without running it
if (err){
  return;
}

err = lua_pcall(L, 0, 0, 0);//run the loaded code block
if (err){
  return;
}

lua_getglobal(L, "name"); //press the value of the global variable name to the top of the stack
printf("%s\n", lua_tostring(L, -1));//take out the top element of the stack and print the result as:muzixiaoxin

lua_close(L); //remember to release when not needed



lua は c メソッドを呼び出します。

luaがcを呼び出すのは、luaが呼び出す固定フォーマットのメソッドを書くのが少し厄介です。

まずは単純に和算のcメソッドを書いてみましょう。

// Calculate the summation method
static int
sum(int a, int b){
  return a + b;
}


このメソッドは、2つの整数の和を求めるものです。luaにこのメソッドを使わせるには、このメソッドをluaステートマシンに登録する必要がありますが、luaステートマシンに登録するメソッドは、固定パラメータと固定戻り値を必要とし、パラメータは、luaから渡されたパラメータを格納するlua仮想スタック、lua呼び出しの戻り値は、この仮想スタックを介してluaに返す必要があり、最終戻り値は、luaに返す変数の数を格納するインテ値でなければなりません。書かれたメソッドを見てみましょう。

//lua calls the method
static int
lsum(lua_State *L){
  int a = (int)lua_tonumber(L, -1);//one of the parameters of the lua call
  int b = (int)lua_tonumber(L, -2);//one of the arguments to the lua call
  lua_pushnumber(L, sum(a, b));//add the calculated to the stack
  return 1;//return the number of returned values
}


次のステップは、メソッドlsumをluaステートマシンに登録することです。

lua_State *L = luaL_newstate();

luaL_openlibs(L);//open all the standard libraries in L so that you can use the print method

lua_register(L, "sum", lsum);//register the c function lsum as a global variable sum of lua

int err = luaL_dofile(L, "test.lua"); //load the lua file as a block of code and run it
if (err){
  return;
}

lua_close(L);



test.luaの中身は。

print("1 + 2 = " . sum(1,2))


最終的に出力されるのは

1+2=3

要約すると、luaの仮想スタックを中間関数(lsumなど)で操作して、cのlua呼び出しを実装する必要があるということです。