この初版は 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. | ![]() |