lua_pcall 函數(shù)
lua_pcall 可以執(zhí)行l(wèi)ua代碼 前面的例子中l(wèi)oad時(shí)就執(zhí)行了lua腳本或者lua編譯文件
int lua_pcall (lua_State *L, int nargs, int nresults, int errfunc);
nargs: 待調(diào)用函數(shù)的參數(shù)數(shù)量
nresults: 期望的結(jié)果個(gè)數(shù)
errfunc: 處理錯(cuò)誤函數(shù)的索引
就像 settop函數(shù)的賦值一樣蚪缀,lua_pcall 會根據(jù)要求的數(shù)量來調(diào)整實(shí)際參數(shù)但狭,即壓入nil或者丟棄多余的結(jié)果。壓入一個(gè)結(jié)果前,lua_pcall會向刪除棧中的函數(shù)以及參數(shù)矛紫。如果一個(gè)函數(shù)有多個(gè)返回值,那么第一個(gè)結(jié)果最先入棧。
如果lua_pcall在運(yùn)行時(shí)有任何錯(cuò)誤,lua_pcall會返回一個(gè)非零值借卧,并且在棧中壓入一條錯(cuò)誤消息。不過即使如此筛峭,它仍然會彈出函數(shù)以及參數(shù)铐刘。然而,在壓入錯(cuò)誤消息前影晓,如果存在一個(gè)錯(cuò)誤處理函數(shù)镰吵,lua_pcall會調(diào)用它。通過lua_pcall的最后一個(gè)參數(shù)可以指定錯(cuò)誤處理函數(shù)挂签。0表示沒有錯(cuò)誤處理函數(shù)疤祭,那么最終的消息就是原來的錯(cuò)誤消息。如果傳入非零值饵婆,那么這個(gè)參數(shù)就應(yīng)該時(shí)一個(gè)處務(wù)處理函數(shù)在棧中的索引勺馆,因此,錯(cuò)誤處理函數(shù)必須先壓入棧中侨核,也就是必須位于待調(diào)用函數(shù)機(jī)器參數(shù)的下面草穆,先其入棧。
對于一個(gè)普通的錯(cuò)誤搓译,lua_pcall返回錯(cuò)誤代碼LUA_ERRRUN悲柱。擔(dān)憂兩種特殊的錯(cuò)誤情況,不會運(yùn)行錯(cuò)誤處理函數(shù)些己。第一種時(shí)內(nèi)存分配錯(cuò)誤豌鸡,這類錯(cuò)誤lua_pcall總是返回LUA_ERRMEM。第二類錯(cuò)誤發(fā)生在lua運(yùn)行錯(cuò)誤處理函數(shù)時(shí)段标,在這種情況沒有必要再次調(diào)用錯(cuò)誤處理函數(shù)直颅,因此lua_pcall會立即返回LUA_ERRERR
代碼示例:
load_func.lua
function f (x, y)
return (x^2 * math.sin(y)) / (1-x)
end
main.cc
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
}
#endif // __cplusplus
static void stack_dump(lua_State *L) {
int i;
int top = lua_gettop(L);//
printf("stack len:%d ", top);
for (i = 1; i <= top; i++) {
int t = lua_type(L, i);
switch (t) {
case LUA_TSTRING: {
printf("'%s'", lua_tostring(L, i));
break;
}
case LUA_TBOOLEAN: {
printf(lua_toboolean(L, i) ? "true" : "false");
break;
}
case LUA_TNUMBER: {
printf("%g", lua_tonumber(L, i));
break;
}
default:
printf("%s", lua_typename(L, t));
break;
}
printf(" ");
}
printf("\n");
}
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);
}
double f(lua_State* L, double x, double y) {
double z;
//壓入函數(shù)和參數(shù)
lua_getglobal(L, "f"); //待調(diào)用的函數(shù)
lua_pushnumber(L, x); //壓入第一個(gè)參數(shù)
lua_pushnumber(L, y); //壓入第二個(gè)參數(shù)
stack_dump(L);
//完成調(diào)用 (2個(gè)參數(shù) 1個(gè)結(jié)果) 執(zhí)行之后,壓入的變量會被彈出
if (lua_pcall(L, 2, 1, 0) != 0) {
error(L, "error running function 'f' :%s \n", lua_tostring(L, -1));
}
stack_dump(L);
//檢索結(jié)果
if (!lua_isnumber(L, -1)) {
error(L, "error running function 'f' must return a number :%s \n", lua_tostring(L, -1));
}
z = lua_tonumber(L, -1);// 彈出結(jié)果
lua_pop(L, 1); //把結(jié)果 以及壓入的函數(shù)和參數(shù)彈出
stack_dump(L);
return z;
}
void load(lua_State* L, const char* fname) {
if (luaL_loadfile(L, fname) || lua_pcall(L, 0, 0, 0)) {
//luaL_loadfile\lua_pcall 發(fā)生錯(cuò)誤怀樟,兩個(gè)函數(shù)都會把錯(cuò)誤消息壓入棧,并返回一個(gè)非零的錯(cuò)誤代碼盆佣,可以通過lua_tostring獲得錯(cuò)誤信息
error(L, "error cannot run config file:%s\n", lua_tostring(L, -1));
}
}
int main() {
lua_State* L = luaL_newstate();
luaL_openlibs(L); //打開標(biāo)準(zhǔn)庫 lualib.h
load(L, "./load_func.lua");
double x = 2.5f;
double y = 3.0f;
double z = 0.0f;
z = f(L, x, y);
printf("function f result is %g \n", z);
lua_close(L);
system("pause");
}