1. 程式人生 > >Stay Hungry.Stay Foolish.

Stay Hungry.Stay Foolish.

      Norman Matloff PeteSalzman在其著作《TheArt of Debugging, withGDB,DDD,Eclipse》中曾說過,確認原則是除錯的本質。程式設計師編寫程式是為實現特定目的,而一個程式可以由許多目的組成,除錯是確認某些目的是否達到了,如果未能達到目的,那麼便可通過在除錯中檢視變數,發現問題癥結,進而解決問題。

    在R中進行debug有幾種不同方式,你如果使用諸如Rstudio等圖形軟體,除錯程式碼很容易,所有的除錯都在圖形介面下完成,你只需要根據需求在圖形介面下點選相應選項來進行斷點設定、單步執行、檢視變數等操作,查詢問題癥結。但如果在命令列介面下除錯

R程式碼,那就得要藉助於一些特別的除錯工具。R的基礎軟體包base中包含了一些基本的除錯工具,當然CRAN中也有一些其它優秀的除錯工具。

    對於一般使用者來說,掌握base中的基本除錯工具就能滿足大部分需求,下面介紹R基本軟體包base中的除錯工具的使用方法(也包含setBreakpoint(),其位於utils包中)

由於在啟動和關閉除錯中需要用到部分除錯命令,這裡就先介紹進入除錯模式後需要用到的一些基本命令。

    1.基本除錯命令

    在進入dedbug除錯狀態後,命令提示符從>變為Browse[d]>(d表示函式呼叫鏈的深度),可以通過一些基本的命令來進行控制

:

  • n(表示next): 告訴R執行下一行程式碼,並且執行完後馬上暫停,實際就是一行一行地執行程式碼。相當於C語言開發工具Turbo C中的trace into
  • c(表示continue):表示會執行若干條語句。若當前處在迴圈中,這一步會執行完整個迴圈,若當前處在函式內但又不再迴圈中,則會執行完當前函式。相當於C語言開發工具Turbo C中的step over
  • where: 輸出一份棧跟蹤路徑,顯示到達當前位置的過程中函式的呼叫序列。
  • Q: 退出brower,返回R的主互動模式。
  • 任意R命令: 即使在除錯狀態browser中,依然處於R的互動模式中,所以你可以用任意R命令。

    2啟動和關閉除錯

    R的核心除錯工具由browser構成,通過browser,你可以逐行執行程式碼,並在執行過程中進行檢查,檢視變數。在除錯程式碼時,我們首先要讓程式進入除錯狀態,有下列幾種方式可以實現。

    2.1 在程式碼中的指定位置加入browser()

開啟除錯:

      在R原始檔中的指定位置插入函式browser(),儲存原始檔,執行源程式,程式一旦執行到browser()處,將會自動進入debug狀態。

   取消除錯:

      但當用戶完成除錯後,需要手動刪除原始檔中的browser()函式,否則每次執行到browser()位置都會進入debug狀態。

       temp_test.R:

           (PS:檔案在下面會多次用到,所以貼出來,但後續用到時已經刪除了browser())

countsum <- function(count)
{
    sum <- 0
    for (i in 1:count)
    {
        sum <- sum + i
    }
    browser()
    return (sum)
}
results <- countsum(100)
print(results)
 
執行之後:
> source("temp_test.R")
Called from: countsum(100)
Browse[1]>


    2.2呼叫debug()

    R的除錯工具是針對單個函式的,由於擁有函數語言程式設計的特性,R的每一個運算子,實際上也是函式(關於R函式,可參考這裡),這裡所說的函式不包括一般的運算子。

 開啟除錯:

      執行命令debug(fun)

            fun指函式名,這樣每次呼叫函式fun()都會進入除錯狀態。

    取消除錯:

       執行命令undebug(fun)

       再次呼叫函式fun()將不會進入除錯狀態。

   如下例所示: 

> source("temp_test.R")
[1] 5050
> debug(countsum)
> countsum(10)
debugging in: countsum(10)
debug at temp_test.R#1: {
    sum <- 0
    for (i in 1:count) {
        sum <- sum + i
    }
    return(sum)
}
Browse[2]> n
debug at temp_test.R#2: sum <- 0
Browse[2]> n
debug at temp_test.R#3: for (i in 1:count) {
    sum <- sum + i
}
Browse[2]> sum
[1] 0
Browse[2]> c
exiting from: countsum(10)
[1] 55


 

    2.3呼叫debugonce()

     debug()的呼叫方式一樣,區別在於:debugonce()只會在設定之後的第一次呼叫時進入除錯狀態且只只進入一次,而debug()可以進入無限多次直到通過undebug()取消除錯。

    2.4用函式trace()進行跟蹤

    trace(fun,tracer)

    fun表示需要跟蹤或者取消跟蹤的函式名;racer表示跟蹤的物件,可以是某個函式,也可以是函式中的某個表示式。

    開啟除錯:

      執行命令trace(fun,tracer)

      每次呼叫函式fun(),都會顯示錶達式的值,或者對函式進行某些操作。

    取消除錯:

      執行命令untrace(fun)

      取消對某個函式的跟蹤。

   如下例所示:

> source("temp_test.R")
[1] 5050
> trace(countsum,sum)
[1] "countsum"
> countsum(10)
Tracing countsum(10) on entry
[1] 55
> untrace(countsum)
> trace(countsum,browser())
Called from:methods::.TraceWithMethods(countsum, browser(), where =<environment>)
Browse[1]> Q
> rm(list = ls())
> source("temp_test.R")
[1] 5050
> trace(countsum,sum)
[1] "countsum"
> countsum(10)
Tracing countsum(10) on entry
[1] 55
> untrace(countsum)
> trace(countsum,browser)
[1] "countsum"
> countsum(20)
Tracing countsum(20) on entry
Called from: eval(expr, envir, enclos)
Browse[1]> n
debug: {
sum <- 0
for (i in 1:count) {
sum <- sum + i
}
return(sum)
}
Browse[2]> c
[1] 210



    2.5.設定斷點setBreakpoint()

    setBreakpoint()位於utils包中,R版本需要>=2.10

    setBreakpoint(filename,linenumber)

  表示會在原始檔filename的第linenumber行設定斷點,但是實際上是通過函式來進行設定的,這點需要注意,即只有所設定的斷點處於檔案中的某個函式內才是有效的。此函式可以用在debug除錯狀態中,在單步除錯過程中,當設定了斷點後,可以讓程式直接執行到到斷點處,這在除錯過程中很有用處。

    開啟除錯:

      執行命令setBreakpoint(filename,linenumber)

      然後執行程式碼,當代碼執行到斷點處即進入除錯狀態。

    取消除錯:

      執行命令untrace(fun)

          fun表示函式名Breakpoint要設在函式內才有效,所以應當通過函式來取消斷點setBreakpoint()是通過呼叫trace()發揮作用的。

   如下例所示:

>source("temp_test.R")
[1]5050
>setBreakpoint("temp_test.R",3)
/home/sheng/WinD/test/temp_test.R#3:
countsumstep 3 in <environment: R_GlobalEnv>
>countsum(20)
temp_test.R#3
Calledfrom: countsum(20)
Browse[1]>n
debug:for (i in 1:count) {
    sum<- sum + i
}
Browse[2]>where
where1: countsum(20)
Browse[2]>sum
[1]0
Browse[2]>c
[1]210

參考:

[1] Norman Matloff著,陳堰平等譯.R語言程式設計藝術.機械工業出版社,2013-05