この初版は Lua 5.0 向けに書かれました。その大部分は依然として後続のバージョンに関連がありますが、若干の違いがあります。
第 4 版は Lua 5.3 を対象としており、Amazon およびその他の書店で購入できます。
本を購入することにより、Lua プロジェクトのサポートにも協力していただけます。
![]() |
プログラミング inLua | ![]() |
パート 4. C API チャプター 25. アプリケーションの拡張 |
より高度な例として、C の vararg
機能を使用して Lua 関数を呼び出すラッパーを構築します。当社のラッパー関数 (call_va と呼びましょう) は、呼び出される関数の名前、引数と結果の型を表す文字列、引数のリスト、最後に結果を格納するための変数へのポインターのリストを受け取ります。ラッパー関数は API のすべての詳細を処理します。この関数を使用すると、前述の例を次のように簡単に記述できます。
call_va("f", "dd>d", x, y, &z);文字列
"dd>d"
は「2 つの double 型の引数と 1 つの double 型の結果」を表します。この記述子は、double には `d
´、整数には `i
´、文字列には `s
´ を使用できます。`>
´ は引数と結果を区切ります。関数が結果を持たない場合、`>
´ は省略できます。#include <stdarg.h> void call_va (const char *func, const char *sig, ...) { va_list vl; int narg, nres; /* number of arguments and results */ va_start(vl, sig); lua_getglobal(L, func); /* get function */ /* push arguments */ narg = 0; while (*sig) { /* push arguments */ switch (*sig++) { case 'd': /* double argument */ lua_pushnumber(L, va_arg(vl, double)); break; case 'i': /* int argument */ lua_pushnumber(L, va_arg(vl, int)); break; case 's': /* string argument */ lua_pushstring(L, va_arg(vl, char *)); break; case '>': goto endwhile; default: error(L, "invalid option (%c)", *(sig - 1)); } narg++; luaL_checkstack(L, 1, "too many arguments"); } endwhile: /* do the call */ nres = strlen(sig); /* number of expected results */ if (lua_pcall(L, narg, nres, 0) != 0) /* do the call */ error(L, "error running function `%s': %s", func, lua_tostring(L, -1)); /* retrieve results */ nres = -nres; /* stack index of first result */ while (*sig) { /* get results */ switch (*sig++) { case 'd': /* double result */ if (!lua_isnumber(L, nres)) error(L, "wrong result type"); *va_arg(vl, double *) = lua_tonumber(L, nres); break; case 'i': /* int result */ if (!lua_isnumber(L, nres)) error(L, "wrong result type"); *va_arg(vl, int *) = (int)lua_tonumber(L, nres); break; case 's': /* string result */ if (!lua_isstring(L, nres)) error(L, "wrong result type"); *va_arg(vl, const char **) = lua_tostring(L, nres); break; default: error(L, "invalid option (%c)", *(sig - 1)); } nres++; } va_end(vl); }この関数は汎用的ですが、前述の例のステップと同様の手順に従います。関数をプッシュし、引数をプッシュし、呼び出しを行い、結果を取得します。コードの大部分は単純ですが、微妙な部分があります。まず、
func
が関数かどうかをチェックする必要はありません。lua_pcall
は、時折発生するエラーをトリガーします。第二に、任意の数の引数をプッシュするため、スタック領域をチェックする必要があります。第三に、関数が文字列を返す可能性があるため、call_va
はスタックから結果をポップできません。呼び出し側は、時折発生する文字列の結果を使用し終えた後 (または別のバッファーにコピーした後) に結果をポップする必要があります。著作権 © 2003–2004 Roberto Ierusalimschy. All rights reserved. | ![]() |