lua本質上利用c函式來操作lua虛擬機器。lua虛擬機器對於c來說只是在堆上的記憶體物件。
lua有自己的執行物件(協程),每個協程有自己的呼叫棧。
比如下面的函式:
function add(x, y)
return x + y
end如果x或y不能進行加法操作,在呼叫中就會產生異常。產生了異常,虛擬機器需要對異常進行處理,最簡單粗暴的處理是直接退出程式。
但這樣肯定是不符合一門現在語言對異常處理能力的要求。lua虛擬機器的做法是把異常交給使用者之前定義的異常處理函式來進行處理。比如是列印出異常資訊,列印出呼叫棧。使用者的異常處理函式處理完以後,虛擬機器還需要恢復到正常的執行流程中。但是恢復到哪一層的呼叫棧,不同時候是不一樣的。虛擬機會從上一層函式開始,直到能找到乙個異常恢復點。找到異常恢復點以後,虛擬機器將程式狀態恢復正常,並從恢復點再次開始執行。
function main()
local c = add(1, nil)
print(c)
end假如上述main函式在呼叫時呼叫棧為
main()
add()
在add函式中出現異常,由於add的上一層沒有異常恢復點,異常會繼續向上丟擲。後面的print語句不會被執行。
function main()
local c
local success, c = pcall(add, x, y)
if success then
print("c is ", c)
else
print("exception accur")
endend上面修改過的main使用了安全呼叫的方式,呼叫add之前,生成了乙個恢復點,當add中出現異常,向上丟擲時,遇到了恢復點,程式恢復到了正常執行狀態。當呼叫中沒有異常發生,pcall會返回true和add的返回值;當發生異常時,pcall會返回false。
在lua.c中異常發生時,預設的異常處理函式會呼叫lual_traceback。它會先列印出異常資訊,然後再列印出呼叫棧。在lua**中,如果需要指定自己的異常處理函式,可以使用xpcall,以第二個引數中傳入自己的異常處理函式。
exp = function (msg) print(msg) end
function main()
local c
local success, c = xpcall(add, exp, x, y)
if success then
print("c is ", c)
else
print("exception accur")
endend在傳入自己的異常處理函式之後,在發生異常時,虛擬機會呼叫該函式,而不是上層的處理函式。
在lua**中可以簡單通過error函式丟擲異常。assert函式相當於對error函式進行了包裝,通過條件判斷是否需要丟擲異常。
function add(x, y)
if type(x) ~= "number" then
error("x is not a number")
endif type(y) ~= "number" then
error("y is not a number")
endend
以math.sin庫為例,呼叫發lual_checknumber函式,如果引數不是乙個數值,則會使用lual_error丟擲異常。
static int math_sin (lua_state *l)
丟擲異常的介面函式大概有:
lualib_api int (lual_argerror) (lua_state *l, int arg, const char *extramsg);
lualib_api int (lual_error) (lua_state *l, const char *fmt, ...);
lua_api int (lua_error) (lua_state *l);
函式luad_rawrunprotected負責建立異常恢復點,具體是通過c語言的setjump設定乙個回跳點,出現異常後,c層直接longjump跳轉到恢復點。而lua層的棧需要由呼叫luad_rawrunprotected的函式自行處理。/**
* u 其實是個 calls 結構指標
* old_top: u 中封裝的真正呼叫函式的棧位置
* ef: 錯誤處理函式的位置
* * 將會以保護模式執行 func(l, u);
*/int luad_pcall (lua_state *l, pfunc func, void *u, ptrdiff_t old_top, ptrdiff_t ef)
l->errfunc = old_errfunc;
return status;
}
lua5 3資料結構
由於lua版本迭代之間,資料結構和函式都會部分變化 以下是我分析的lua.h中的資訊,以便確定版本 define lua version major 5 define lua version minor 3 define lua version num 503 define lua version ...
Lua5 3遇到的坑
attempt to call a nil value global unpack 在lua 5.2和5.3的版本中,全域性的unpack函式已經被移除了,改為table.unpack,所以如果用到的第三方庫或者源 使用了unpack方法,可以在 前面加上 local unpack unpack o...
lua 5 3開發除錯環境搭建
目錄 5.1 以後就沒有很好的lua ide可用了,luastudio不錯但是小貴,發現有位仁兄寫了個 visual studio code的lua除錯外掛程式,試了一下還不錯 外掛程式原始碼 安裝lua 5.3 debug 外掛程式,在vscode中按ctrl p,輸入 ext install l...