Octave 中有許多用來輸出錯誤與警告訊息的函數,在使用者自行定義的函數中若是碰到異常的狀況,可以使用這裡介紹的函數來輸出錯誤或警告訊息。

由於 Octave 中大部份的函數都有使用這些錯誤與警告函數,因此了解這些函數的運作有助於使用者處理 Octave 所產生的錯誤與警告。

錯誤處理(Handling Errors)

錯誤(errors)是指程式發生無法繼續執行或繼續執行已經無意義的情況,例如呼叫函數時輸入的參數太少的情況,在這種情況下函數應該要輸出錯誤訊息,以通知使用者缺少的輸入參數。

產生錯誤(Raising Errors)

最常見的錯誤就是當函數的輸入參數不符合的情況,下面的函數 f() 會在沒有輸入參數的情況以 error() 函數產生錯誤:

function f (arg1)
  if (nargin == 0)
    error("not enough input arguments");
  endif
endfunction

error() 函數被呼叫後,會產生指定的錯誤訊息,並停止執行目前的程式,回到命令列,有就是說在 error() 函數之後的程式碼將不會被執行。

error (template, ...)
error (id, template, ...)

error() 函數會依照指定的格式將錯誤訊息輸出至標準錯誤(stderr),其格式的指定方式與 printf() 函數相同,而在輸出時會自動在每一行的開頭加上 "error: "。呼叫 error() 函數也會一並設置 Octave 內部的錯誤狀態,因此 Octave 會直接回到最上層的命令列,不會再執行任何的程式碼,這在取消執行函數或指令稿的時候很有用。

error() 函數所指定的錯誤訊息沒有以換行字元結尾,Octave 會自動輸出所有呼叫函數的 traceback,例如:

function f () g (); end
function g () h (); end
function h () nargin == 1 || error ("nargin != 1"); end

執行 f() 函數時所輸出的 traceback 訊息可以協助使用者很快的找出錯誤的發生點:

f()

輸出的 traceback 訊息為

error: nargin != 1
error: called from:
error:   h at line 1, column 27
error:   g at line 1, column 15
error:   f at line 1, column 15

error() 函數所指定的錯誤訊息是以換行字元結尾,則 Octave 只會輸出指定的錯誤訊息,不會輸出 traceback,例如將上面的 h() 函數改為:

function h () nargin == 1 || error ("nargin != 1\n"); end

則執行 f()

f()

輸出的訊息變為:

error: nargin != 1

由於處理函數輸入參數錯誤的情況很常見,因此 Octave 中提供了一個 print_usage() 函數專門用來處理這樣的狀況,當 print_usage() 函數被呼叫時,它會讀取呼叫它的函數的開頭註解,並輸出詳細的錯誤訊息:若函數說明是 Texinfo 的格式,則會輸出其中 @deftypefn 所定義的函數原型(prototype);若函數的說明不是 Texinfo 格式,則輸出的錯誤訊息會包含所有的函數說明。例如:

## -*- texinfo -*-
## @deftypefn {Function File} f (@var{arg1})
## Function help text goes here...
## @end deftypefn
function f (arg1)
  if (nargin == 0)
    print_usage ();
  endif
endfunction

若執行 f() 函數沒有輸入參數時,則會輸出錯誤訊息:

f()

輸出的錯誤訊息為

error: Invalid call to f.  Correct usage is:

 -- Function File: f (ARG1)


Additional help for built-in functions and operators is
available in the on-line version of the manual.  Use the command
`doc ' to search the manual index.

Help and information about Octave is also available on the WWW
at http://www.octave.org and via the help@octave.org
mailing list.
print_usage ()
print_usage (name)

print_usage() 函數可以輸出參數 name 所指定的函數的使用說明,若省略 name 參數則會輸出目前函數的使用說明。

usage (msg)

usage(msg) 函數會將 msg 中訊息的每一行開頭加上 "usage: " 後輸出,並設置 Octave 內部的錯誤狀態,跳過之後所有的程式碼回到最上層的命令列,這個函數亦可用於中斷執行中的函數。當呼叫 usage() 函數後,Octave 也會輸出函數呼叫的 traceback。

當函數以不正確的參數呼叫時,可以使用 usage() 函數輸出適當的錯誤訊息,例如大部分的 Octave 內建函數的開頭都會使用類似這樣的程式碼來檢查輸入的參數個數:

if (nargin != 2)
  usage ("foo (a, b)");
endif

這樣當使用者所輸入的參數有問題時,可以輸出適當的訊息指引使用者如何使用此函數。

beep ()

beep() 函數可以讓喇叭產生一個嗶聲(beep)。

val = beep_on_error ()
old_val = beep_on_error (new_val)

beep_on_error() 函數可以查詢或設定是否要在錯誤訊息輸出前產生一個嗶聲。

獲取錯誤(Catching Errors)

當錯誤發生時,可以使用 try 敘述來處理錯誤(請參考 try 敘述),例如下面的範例會計算在迴圈中發生幾次錯誤:

number_of_errors = 0;
for n = 1:100
  try
    # ...
  catch
    number_of_errors++;
  end_try_catch
endfor

上面這個範例中對於所有的錯誤都使用同一種處理方式,但有時候會需要針對不同的錯誤做不同的處理,此時可以使用 lasterror() 函數來判斷錯誤的類型,此函數會傳回包含最後一次錯誤資訊的資料結構,例如上面的範例可以修改為計算乘法運算子出現錯誤的次數:

number_of_errors = 0;
for n = 1:100
  try
    # ...
  catch
    msg = lasterror.message;
    if (strfind (msg, "operator *"))
      number_of_errors++;
    endif
  end_try_catch
endfor
err = lasterror (err)
lasterror ('reset')

lasterror() 函數可以設定或傳回包含最後一次的錯誤資訊的資料結構,此資料結構的欄位如下:

  • message:錯誤訊息。
  • identifier:錯誤的辨識碼。
  • stack:包含錯誤發生位置的資料結構,當此資訊無法取得時,會是一個空的資料結構。以下是資料結構的欄位:
    • file:錯誤發生處的檔案名稱。
    • name:錯誤發生處的函數名稱。
    • line:錯誤發生處的行數。
    • column:錯誤發生處的字元數。

這個 err 資料結構也可以當作 lasterror() 函數的傳入參數,以設定最後一次的錯誤資訊,此傳入的資料結構唯一的限制就是必須為純量的資料結構,而此傳入的資料結構中若是其欄位名稱符合上面所列的這些欄位,則會將其值設為傳入資料結構中欄位中對應的值,其餘的值維持預設值。

lasterror() 的傳入參數為 'reset',則會將所有的值設為預設值。

[msg, msgid] = lasterr (msg, msgid)

lasterr() 函數可以查詢或設定最後一次的錯誤訊息與錯誤的辨識碼,若呼叫時沒有任何輸入參數,則會傳回最後一次的錯誤訊息,若設定 msg 參數,則會將最後一次的錯誤訊息設定為 msg,若再加上 msgid 參數則會再設定錯誤的辨識碼。

當錯誤被 catch 敘述處理之後,亦可以重新丟出錯誤,當錯誤被處理之後還是需要終止程式執行的情況,就可以使用重新丟出錯誤的方式處理。

要重新丟出錯誤可以使用 rethrow() 函數,上一個範例可以改成:若是乘法運算子出現錯誤,則計算其次數,否則就終止程式的執行:

number_of_errors = 0;
for n = 1:100
  try
    # ...
  catch
    msg = lasterror.message;
    if (strfind (msg, "operator *"))
      number_of_errors++;
    else
      rethrow (lasterror);
    endif
  end_try_catch
endfor
rethrow (err)

rethrow(err) 函數會將 err 錯誤重新丟出,err 是一個至少包含 messageidentifier 欄位的資料結構,另外亦可包含 stack 欄位(欄位的說明請參考上面 lasterror() 函數的說明),一般來說 err 可以由 lasterror() 函數取得。

err = errno ()
err = errno (val)
err = errno (name)

errno() 函數可以傳回系統變數 errno 目前的值,若傳入一個數值參數 val 則會將系統變數 errno 設定為 val;若傳入一個字串參數 name 則會傳回此名稱所對應的錯誤代碼,若找不到則傳回 -1,例如:

errno("EIO")

輸出為

ans =  5
errno_list ()

errno_list() 函數會傳回一個資料結構,其中包含系統變數 errno 所有可能的錯誤代碼。