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 所有可能的錯誤代碼。

警告處理(Handling Warnings)

警告(warnings)與錯誤類似,都是用來通知使用者有一些預期之外的情況發生,但不同的是警告不會中斷目前所執行的程式。例如在數值除以零的的情況,Octave 會產生一個警告並將結果設為無限大(Inf):

a = 1/0

輸出為

warning: division by zero
a = Inf

產生警告(Issuing Warnings)

警告(warnings)可以使用 warning() 函數來產生,最簡單的方式就是輸入一個描述警告的字串參數,例如下面的程式碼會在變數 a 的值為負的情況下產生警告,並將 a 設為0

a = -1;
if (a < 0)
  warning ("'a' must be non-negative.  Setting 'a' to zero.");
  a = 0;
endif

執行的輸出為

warning: 'a' must be non-negative.  Setting 'a' to zero.

由於警告對於程式的執行是沒有直接影響的,所以其沒有類似錯誤 trycatch 敘述的處理方式,只能使用 lastwarn() 函數取得最後一次的警告資訊。

warning() 函數亦可使用警告代碼來指定所要產生的警告,或是將指定的警告啟動或關閉。

warning (template, ...)
warning (id, template, ...)
warning ("on", id)
warning ("off", id)
warning ("error", id)
warning ("query", id)

warning(template, ...) 函數會依照 template 所指定的格式將錯誤訊息輸出至標準錯誤(stderr),其格式的指定方式與 printf() 函數相同,而在輸出時會自動在每一行的開頭加上 "warning: "。這個函數用於告知使用者有不正常的狀況發生,但是程式還是會繼續執行下去。

其中 id 參數是警告代碼,使用者可以使用此代碼來啟動或關閉指定的警告,若指定為 "all" 則表示全部的警告。

warning("query", id) 可以查詢 id 所指定的警告的狀態,若省略 id 參數則預設為 "all"(即所有的警告)。warning("query", id) 是將 id 所指定的警告狀態設定為錯誤,這樣會使這個警告被當作一個錯誤來處理。

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

lastwarn() 函數若不輸入任何參數則會傳回最後一次的警告訊息,若指定 msg 參數則會將最後一次的警告訊息設定為 msg,若再加上 msgid 參數則會一並將最後一次的警告代碼設定為 msgid

啟用與關閉警告(Enabling and Disabling Warnings)

warning() 函數可以控制哪一些警告要輸出至螢幕上,若呼叫此函數只有傳入一個 "on""off" 參數,則會啟動或關閉所有的警告。若要控制指定的警告,可以使用警告的代碼,例如下面這個程式碼會產生警告:

warning ("non-negative-variable", "'a' must be non-negative.  Setting 'a' to zero.");

而下面這個則會將警告關閉:

warning ("off", "non-negative-variable");
warning ("non-negative-variable", "'a' must be non-negative.  Setting 'a' to zero.");

下面是 Octave 中內建函數所使用的警告:

Octave:array-to-scalar

若開啟 Octave:array-to-scalar 警告,則當陣列要被自動轉換成純量時,就會產生警告,此警告預設為關閉。

Octave:array-to-vector

若開啟 Octave:array-to-vector 警告,則當陣列要被自動轉換成向量時,就會產生警告,此警告預設為關閉。

Octave:assign-as-truth-value

若開啟 Octave:assign-as-truth-value 警告,則 Octave 碰到下面這樣的程式碼就會產生警告:

if (s = t)
  # ...

因為這樣的程式碼通常是因為少寫了一個等於符號,應該是要寫成這樣才合理:

if (s == t)
  # ...

然而將指定算子放在 whileif 敘述中也是一種常見的寫法,由其在 C 語言中,例如:

while (c = getc())
  # ...

在這種情況下若開啟 Octave:assign-as-truth-value 警告,Octave 也會產生警告訊息,但將此警告關閉又會容易忽略掉漏寫等號的問題,要處理這樣的情況可以將有使用指定運算子的地方再加入一個額外的小括號,這樣就可以避免產生警告訊息,例如上面的例子就可以寫成這樣:

while ((c = getc()))
  # ...

這樣即可避免產生警告訊息,亦可以讓 Octave 檢查其他地方是否有漏寫等號。

Octave:assign-as-truth-value 警告預設是開啟的。

Octave:associativity-change

若開啟 Octave:associativity-change 警告,當運算子的關聯性改變會對程式的解讀造成影響時,Octave 就會提出警告,運算子關聯性改變一般都是為了與 Matlab 相容,預設 Octave:associativity-change 警告式開啟的。

Octave:divide-by-zero

若開啟 Octave:divide-by-zero 警告,則當 Octave 遇到一個數值除以零的時候就會產生警告,預設為開啟。

Octave:empty-list-elements

若開啟 Octave:empty-list-elements 警告,當使用中括號建立矩陣時,若中括號中有包含空矩陣,則會提出警告,例如:

a = [1, [], 3, [], 5]

Octave:empty-list-elements 警告預設是開啟的。

Octave:fortran-indexing

若開啟 Octave:fortran-indexing 警告,則在使用單一個索引存取二維的矩陣時,就會提出警告,此警告預設為關閉。

Octave:function-name-clash

若開啟 Octave:function-name-clash 警告,當 Octave 發現一個定義在函數檔案中的函數,其函數名稱與檔案名稱不同時(若函數名稱與檔案名稱不同,則此函數會被忽略),就會提出警告,此警告預設為開啟。

Octave:future-time-stamp

若開啟 Octave:future-time-stamp 警告,當 Octave 發現有函數檔案的時間戳記是未來的時間時,就會提出警告,此警告預設為開啟。

Octave:imag-to-real

若開啟 Octave:imag-to-real 警告,則當一個複數自動轉換為實數時就會提出警告,此警告預設為關閉。

Octave:matlab-incompatible

若開啟 Octave:matlab-incompatible 警告,則當有可能會出現 Matlab 相容性問題時,就會提出警告。

Octave:missing-semicolon

若開啟 Octave:missing-semicolon 警告,當函數中的敘述沒有以分號結尾時,就會提出警告,此警告預設為關閉。

Octave:neg-dim-as-zero

若開啟 Octave:neg-dim-as-zero 警告,當遇到維度為負的時候,就會提出警告,例如:

eye (-1)

Octave:neg-dim-as-zero 警告預設為關閉。

Octave:num-to-str

若開啟 Octave:num-to-str 警告,當數值自動轉換成對應的 ASCII 字元時,就會提出警告,此警告預設為開啟。

Octave:precedence-change

若開啟 Octave:precedence-change 警告,當優先權的改變會對於程式的解讀造成影響時,Octave 就會提出警告,優先權的改變一般都是為了與 Matlab 相容,此警告預設為開啟。

Octave:reload-forces-clear

當有多個函數已經從一個檔案中載入時,若要重新載入此檔案中的任何一個函數,必須先將這些已經載入的函數清除,若開啟 Octave:reload-forces-clear 警告,則當要清除這些以載入的函數時,就會提出警告,並列出所有會被清除的函數,此警告預設為開啟。

Octave:resize-on-range-error

若開啟 Octave:resize-on-range-error 警告,當矩陣變換其大小時,若定的大小不在目前的範圍內,則會提出警告,此警告預設為關閉。

Octave:separator-insert

若開啟 Octave:separator-insert 警告,則當字元矩陣中會被自動安插逗號或是分號時,就會提出警告。

Octave:single-quote-string

若開啟 Octave:single-quote-string 警告,則當單引號字串用於常數字串時,就會提出警告。

Octave:str-to-num

若開啟 Octave:str-to-num 警告,則當字串自動依照 ASCII 轉換為數值時,就會提出警告,例如:

"abc" + 0

Octave:str-to-num 警告預設為關閉。

Octave:string-concat

若開啟 Octave:string-concat 警告,若混合單引號與雙引號的字串使用時,就會提出警告,此警告預設為關閉。

Octave:undefined-return-values

若開啟 Octave:undefined-return-values 警告,若在函數中沒有定義所有呼叫時所指定的傳回值,就會提出警告,此警告預設為開啟。

Octave:variable-switch-label

若開啟 Octave:variable-switch-label 警告,若在 switch 的敘述中 label 不是一個常數或常數算式,就會提出警告,此警告預設為關閉。