vs2013+lua5.3.3函數
1.涉及函數測試
主要C函數:lua_call和lua_pcallui
主要lua函數xpcalllua
2.正常使用lua_callspa
①hello.lua文件內容debug
function ccall_test_func(val) print(string.format("ccall_test_func val = %d",val)) end
②C++文件內容(主要內容在test_func函數中的lua_call函數,表示調用lua中的ccall_test_func函數,並將值1傳給val)調試
//這個頭文件包含了所需的其它頭文件
#include "lua.hpp"
//測試函數
void test_func(lua_State* L){ lua_getglobal(L, "ccall_test_func"); lua_pushinteger(L, 1); lua_call(L, 1, 0);//調用
} static const luaL_Reg lua_reg_libs[] = { { "base", luaopen_base }, { "coroutine", luaopen_coroutine }, { "table", luaopen_table }, { "io", luaopen_io }, { "os", luaopen_os }, { "string", luaopen_string }, { "utf8", luaopen_utf8 }, { "math", luaopen_math }, { "debug", luaopen_debug }, { "package", luaopen_package }, { NULL, NULL } }; int main(int argc, char* argv[]) { if (lua_State* L = luaL_newstate()){ //註冊讓lua使用的庫
const luaL_Reg* lua_reg = lua_reg_libs; for (; lua_reg->func; ++lua_reg){ luaL_requiref(L, lua_reg->name, lua_reg->func, 1); lua_pop(L, 1); } //加載腳本,若是出錯,則打印錯誤
if (luaL_dofile(L, "hello.lua")){ std::cout << lua_tostring(L, -1) << std::endl; } test_func(L); //調用測試函數
lua_close(L); } else{ std::cout << "luaL_newstate error !" << std::endl; } system("pause"); return 0; }
③運行後正常輸出結果code
3.使用lua_call產生的問題orm
①將lua中文件的ccall_test_func函數修改成拋出一個error,以下: 對象
function ccall_test_func(val) print(string.format("ccall_test_func val = %d",val)) error("throw error") --新增長一行模擬拋出錯誤
end
②運行後,直接拋出錯誤了
4.方法一:使用lua的保護模式函數xpcall處理錯誤
①將hello.lua文件中的ccall_test_func函數修改成
function ccall_test_func(val) --將函數調用修改成局部函數
local function lua_test_func(val) print(string.format("ccall_test_func val = %d",val)) error("throw error") --新增長一行模擬拋出錯誤
end
--調用保護函數xpcall
local status, err_msg = xpcall( function(v) lua_test_func(v) end, --調用局部函數,v的值由下面的val提供
function(msg) local ret_msg = debug.traceback(msg, 3) ret_msg = string.format("xpcall val = %d \n%s", val, ret_msg) return ret_msg end, --結合debug.traceback獲得系統內部提供的堆棧信息msg,並將ret_msg做爲xpcall的返回值
val) --傳給v
if not status then
print(err_msg) end
end
②簡化一下
③正常運行效果
5.方法二:使用C++的保護模式函數lua_pcall處理錯誤
①在hello.lua中增長一個由C++調用的錯誤處理函數ccall_err_handler
function ccall_test_func(val) print(string.format("ccall_test_func val = %d",val)) error("throw error") --新增長一行模擬拋出錯誤
end
--增長的C++調用的錯誤處理函數
function ccall_err_handler(msg) print(debug.traceback(msg,3)) end
②修改C++中的test_func函數,使用保護模式函數lua_pcall
//測試函數
void test_func(lua_State* L){ lua_getglobal(L, "ccall_err_handler"); lua_getglobal(L, "ccall_test_func"); lua_pushinteger(L, 1); lua_pcall(L, 1, 0, -3);//調用ccall_test_func,當出現錯誤時,會將error msg放在棧頂-1位置讓放置在-3位置的錯誤處理函數ccall_err_handler使用
}
②簡化一下
function ccall_test_func(val) --將函數調用修改成局部函數 local function lua_test_func(val) print(string.format("ccall_test_func val = %d",val)) error("throw error") --新增長一行模擬拋出錯誤 end --錯誤處理函數 local function error_handler(msg) local ret_msg = debug.traceback(msg, 3) ret_msg = string.format("xpcall val = %d \n%s", val, ret_msg) return ret_msg end local status, err_msg = xpcall( lua_test_func, --參數只有後面值val的話,這裏能夠直接使用函數名 error_handler, --參數只有msg的話(若是有其它傳入參數,則須要使用上面的方式),這裏能夠直接使用函數名 val) --傳給val if not satus then print(err_msg) end end
③正常運行效果
6.使用lua_pcall,增長輸出用戶信息
①從上面能看到,lua_pcall也能處理異常的狀況,可是在異常信息裏只包含了堆棧信息,沒有對用戶數據的描述
②修改hello.lua的錯誤處理函數,增長參數接收val的值
-- 增長的C++調用的錯誤處理函數
function ccall_err_handler(val, msg) local err_msg = string.format("ccall_err_handler val = %d \n%s", val, msg) -- 這裏使用debug.traceback不起做用,由於棧已經展開,因此收集不到棧跟蹤信息了
print(err_msg) end
③修改一下C++中的test_func函數,以下
//測試函數
void test_func(lua_State* L){ lua_getglobal(L, "ccall_test_func"); lua_pushinteger(L, 1); if (lua_pcall(L, 1, 0, 0)){ //若是此時出現錯誤,則當前-1位置爲error msg
lua_getglobal(L, "ccall_err_handler"); //error msg變爲-2
lua_pushinteger(L, 1); //增長用戶數據信息 //error msg變爲-2
lua_pushvalue(L, -3); //將-3位置的error msg 放置爲-1位置
lua_pcall(L, 2, 0, 0); } }
④正常運行效果
上面能夠看到數據信息以及錯誤信息了,可是堆棧跟蹤信息收集不到了。
綜上所述:通常狀況下,建議使用方法一,簡單方便並且信息全。
如下兩點來自於 《Lua 5.3 參考手冊》中文版 譯者 雲風 製做 Kavcc
7.lua_pcall函數介紹
int lua_pcall (lua_State *L, int nargs, int nresults, int msgh);
以保護模式調用一個函數。
nargs 和 nresults 的含義與 lua_call 中的相同。 若是在調用過程當中沒有發生錯誤, lua_pcall 的行爲和 lua_call 徹底一致。 可是,若是有錯誤發生的話, lua_pcall 會捕獲它, 而後把惟一的值(錯誤消息)壓棧,而後返回錯誤碼。 同 lua_call 同樣, lua_pcall 老是把函數自己和它的參數從棧上移除。
若是 msgh 是 0 , 返回在棧頂的錯誤消息就和原始錯誤消息徹底一致。 不然, msgh 就被當成是 錯誤處理函數 在棧上的索引位置。 (在當前的實現裏,這個索引不能是僞索引。) 在發生運行時錯誤時, 這個函數會被調用而參數就是錯誤消息。 錯誤處理函數的返回值將被 lua_pcall 做爲錯誤消息返回在堆棧上。
典型的用法中,錯誤處理函數被用來給錯誤消息加上更多的調試信息, 好比棧跟蹤信息。 這些信息在 lua_pcall 返回後, 因爲棧已經展開,因此收集不到了。
lua_pcall 函數會返回下列常數 (定義在 lua.h 內)中的一個:
LUA_OK (0): 成功。
LUA_ERRRUN: 運行時錯誤。
LUA_ERRMEM: 內存分配錯誤。對於這種錯,Lua 不會調用錯誤處理函數。
LUA_ERRERR: 在運行錯誤處理函數時發生的錯誤。
LUA_ERRGCMM: 在運行 __gc 元方法時發生的錯誤。 (這個錯誤和被調用的函數無關。)
8.關於lua的錯誤處理
因爲 Lua 是一門嵌入式擴展語言,其全部行爲均源於宿主程序中 C 代碼對某個 Lua 庫函數的調用。 (單獨使用 Lua 時,lua 程序就是宿主程序。) 因此,在編譯或運行 Lua 代碼塊的過程當中,不管什麼時候發生錯誤, 控制權都返回給宿主,由宿主負責採起恰當的措施(好比打印錯誤消息)。
能夠在 Lua 代碼中調用 error 函數來顯式地拋出一個錯誤。 若是你須要在 Lua 中捕獲這些錯誤, 可使用 pcall 或 xpcall 在 保護模式 下調用一個函數。
不管什麼時候出現錯誤,都會拋出一個攜帶錯誤信息的 錯誤對象 (錯誤消息)。 Lua 自己只會爲錯誤生成字符串類型的錯誤對象, 但你的程序能夠爲錯誤生成任何類型的錯誤對象, 這就看你的 Lua 程序或宿主程序如何處理這些錯誤對象。
使用 xpcall 或 lua_pcall 時, 你應該提供一個 消息處理函數 用於錯誤拋出時調用。 該函數需接收原始的錯誤消息,並返回一個新的錯誤消息。 它在錯誤發生後棧還沒有展開時調用, 所以能夠利用棧來收集更多的信息, 好比經過探知棧來建立一組棧回溯信息。 同時,該處理函數也處於保護模式下,因此該函數內發生的錯誤會再次觸發它(遞歸)。 若是遞歸太深,Lua 會終止調用並返回一個合適的消息。