Lua 5.3を素早く把握する-あなたのプログラムを拡張する(2)
12421 ワード
Q:Luaの関数をCで呼び出すには?
A:1、Lua関数をスタックに入れる.2、パラメータをパラメータ順にスタックに順次入れる.3、関数を呼び出します.呼び出しが完了すると、関数のパラメータとLua関数がスタックされ、関数の戻り値がスタックされます.4、関数の戻り値を取得します.「config.lua」ファイル:
main.cファイル:
Q:CでLua関数を呼び出す形で、C++のような関数のリロードを実現するにはどうすればいいですか?
A:上記の例のプログラムを拡張し続けます(この例ではJNIの呼び出しに似ているものもあります)、「main.c」ファイルでは、
追加:
1、
A:1、Lua関数をスタックに入れる.2、パラメータをパラメータ順にスタックに順次入れる.3、関数を呼び出します.呼び出しが完了すると、関数のパラメータとLua関数がスタックされ、関数の戻り値がスタックされます.4、関数の戻り値を取得します.「config.lua」ファイル:
function f(x, y)
return (x ^ 2 * math.sin(y)) / (1 - x)
end
main.cファイル:
#include
#include
#include
#include
#include
#include
void error(lua_State *L, const char *fmt, ...)
{
va_list argp;
va_start(argp, fmt);
vfprintf(stderr, fmt, argp);
va_end(argp);
lua_close(L);
exit(EXIT_FAILURE);
}
void load(lua_State *L, char *filename)
{
if(luaL_loadfile(L, filename) || lua_pcall(L, 0, 0, 0))
error(L, "cannot run configuration file: %s", lua_tostring(L, -1));
}
// Lua 。
double f(lua_State *L, double x, double y)
{
double z = 0.0;
lua_getglobal(L, "f"); // Lua Lua , 。
// Lua 。
lua_pushnumber(L, x);
lua_pushnumber(L, y);
if(lua_pcall(L, 2, 1, 0) != 0) // ,2 ,1 。
error(L, "error running function `f': %s", lua_tostring(L, -1));
if(!lua_isnumber(L, -1)) // 。
error(L, "function `f' must return a number");
z = lua_tonumber(L, -1);
lua_pop(L, 1); // , 。
return z;
}
int main(void)
{
lua_State *L = luaL_newstate();
luaL_openlibs(L);
load(L, "config.lua");
printf("%f
", f(L, 0.5, 0.5));
lua_close(L);
return 0;
}
prompt> gcc main.c -llua -ldl -lm -Wall
prompt> ./a.out
0.239713
Q:CでLua関数を呼び出す形で、C++のような関数のリロードを実現するにはどうすればいいですか?
A:上記の例のプログラムを拡張し続けます(この例ではJNIの呼び出しに似ているものもあります)、「main.c」ファイルでは、
#include
#include
#include
#include
#include
#include
#include
#include
void error(lua_State *L, const char *fmt, ...)
{
va_list argp;
va_start(argp, fmt);
vfprintf(stderr, fmt, argp);
va_end(argp);
lua_close(L); // Lua 。
exit(EXIT_FAILURE); // 。
}
void load(lua_State *L, char *filename)
{
if(luaL_loadfile(L, filename) || lua_pcall(L, 0, 0, 0))
error(L, "cannot run configuration file: %s", lua_tostring(L, -1));
}
/* "func": Lua 。
* "sig": 。
'd': double。
'i': integer。
's': string。
'>': 。 , 。
* "...": 。
*/
void call_va(lua_State *L, const char *func, const char *sig, ...)
{
va_list vl;
int narg = 0, nres = 0; // 。
va_start(vl, sig);
lua_getglobal(L, func); // Lua 。
narg = 0;
while(*sig) // , 。
{
switch(*sig++)
{
case 'd': /* double argument */
lua_pushnumber(L, va_arg(vl, double));
break;
case 'i': /* int argument */
lua_pushinteger(L, va_arg(vl, int));
break;
case 's': /* string argument */
lua_pushstring(L, va_arg(vl, char *));
break;
case '>': // , "while"。
goto endwhile;
default:
error(L, "invalid option(%c)", *(sig - 1));
}
narg++;
/* 1。 ( ), 。
* ("NULL" )。
* , , 。
*/
luaL_checkstack(L, 1, "too many arguments");
}
endwhile:
nres = strlen(sig); // 。
if(lua_pcall(L, narg, nres, 0) != 0)
error(L, "error running function `%s': %s", func, lua_tostring(L, -1));
nres = -nres; // , 。
while(*sig) // 。
{
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_isinteger(L, nres))
error(L, "wrong result type");
*va_arg(vl, int *) =(int)lua_tointeger(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);
}
int main(void)
{
double z = 0.0f;
lua_State *L = luaL_newstate();
luaL_openlibs(L);
load(L, "config.lua");
// Lua "f" , , , "z" 。
call_va(L, "f", "ds>d", 0.5, "0.5", &z);
printf("%f
", z);
lua_close(L);
return 0;
}
prompt> gcc main.c -llua -ldl -lm -Wall
prompt> ./a.out
0.239713
追加:
1、
call_va()
で指定された「func」がLuaの有効な関数であるか否かを判断する必要はなく、lua_pcall()
でこのエラーをキャプチャすることができる.2.Lua関数の戻り値は文字列である可能性があるため、call_va()
では戻り値をスタックから出すことができない.この作業では、呼び出し元が戻り値を転送した後、手動で結果をスタックから出す必要があります.