1. 程式人生 > >除錯及遞迴函式除錯之思考.

除錯及遞迴函式除錯之思考.

除錯之思考以及遞迴函式除錯之思考!
------------------------------------------------------------
author: hjjdebug
date: 2017年 12月 27日
------------------------------------------------------------
除錯之總結(包活正向除錯或逆向除錯)
編寫->編譯->除錯 繼續簡化為編寫->除錯 或者說修改->除錯迴圈.
除錯是修改的基礎,除錯此時佔主導性.
那麼何為除錯,怎麼除錯呢?
除錯是給定一個輸入,必須看到期望的輸出. 此時輸入是已知的,輸出也是已知的,
以此來檢查處理的過程.

除錯的目標:
工作的目標可以有大目標,小目標,但除錯的目標必須是可執行的.除錯到指定位置
期望的輸出通常是一個或一組資料,一個或一組已知的字串.
除錯的目標也可以設定為程式執行的路徑資訊,函式引數資訊等
我也常常在想,到底到底要怎樣除錯,達到怎樣的目的!

除錯的前提:
一般固定的輸入容易獲得, 期望的輸出, 可以通過手工計算,可以通過其它程式計算.
如果有一個正確的路徑可以參考,那自然要利用這個柺杖啦!

除錯的方法:
具體的方法依賴於除錯的環境. 但大體上還是中斷,單步,跟蹤,及列印log等手段
其中在何處中斷,需要技巧.是後續單步的基礎.
有時候,需要構建一個小巧的除錯模型,過濾掉多餘的,不重要的資料,達到簡介除錯的目的
列印log,是一種比較有效率的方法,是計算機與人有效溝通的手段.
靈活運用以上手段,快速解決問題,是除錯能力的判定依據.
IDA 就有一個不錯的偵錯程式,你可以與它對話!

遞迴程式除錯方法:
------------------------------------------------------------
author: hjjdebug
date: 2017年 12月 27日
------------------------------------------------------------
面對一個複雜的被除錯程式,如何才能快速理解其資料目的及目標.
例如,我碰到了一個複雜的遞迴呼叫程式,4個入口,7個出口,7個引數.
這個是個直接的遞迴,呼叫都集中在一個函式裡.
還碰到過間接遞迴,函式呼叫了別的函式,別的函式又反過來呼叫這個函式,
其中分支呼叫函式不記其數. 這種應該是更復雜的.
獨立的分支呼叫不是我們關心的目標,但回過頭來呼叫遞迴的函式是需要考慮的.
遞迴函式易寫難調, 易寫是因為你只需寫退出條件,寫遞迴函式即可.難調是因為
其執行流程不是線性的,當你執行到遞迴函式時,它會逐層展開,形成一個呼叫樹
直到退出條件,再逐層返回,如果是單步跟蹤,跟不了幾步,往往就會騰雲駕霧,不知
自己身處何處.
既然遞迴的呼叫多了一個深度的概念, 好,
手段1,我們用一個glevel變數跟蹤其深度,每遞迴一層,glevel++,
    遞迴函式return時, glevel--, 這樣就能定位遞迴函式的深度.
手段2,列印遞迴函式的入口位置,
手段3,列印其它關心的資料.

總之,就是新增列印資訊嗎,通過列印,找到我們關心的資訊和搞通呼叫關係.
為了簡化程式的修改方法,可以使用巨集替代語句.
我為自己找到的這種方法應該說自己想到和實踐的方法而沾沾自喜!

附上2個例項,是我用過的. 留作紀念!
我很少使用巨集,但發現在這個地方使用巨集是非常的方便和有效! 它有效解決了函式呼叫和返回值問題.

#ifdef _USE_MACRO_CALL
#define mac_realScan(a1,a2,e) ({printf("rs in:glevel:%d i_e:%d\n",++glevel,e); \
        printf("filename:%s\n",((MapFile *)a1)->filename);\
        macRet=realScan(a1,a2); printf("rs rtn:%p\n",macRet);macRet;})
#define mac_rs_rtn(a1,e) ({if(a1){printf("nodes:%d\n",((F2_36*)a1)->list0->node_size);}\
        printf("rs out:glevel:%d o_e:%d\n",--glevel,e); return a1;})
#else
#define mac_realScan(a1,a2,e) ({ macRet=realScan(a1,a2); macRet;})
#define mac_rs_rtn(a1,e) ({ return a1;})
#endif


相關推薦

除錯函式除錯思考.

除錯之思考以及遞迴函式除錯之思考! ------------------------------------------------------------ author: hjjdebug date: 2017年 12月 27日 --------------------

JS學習函式表示式(一)宣告

一.函式宣告 函式表示式是JavaScript中的一個既強大有容易令人困惑的特性。定義函式的方式有兩種:一是函式宣告,二是函式表示式 函式宣告如下,這種定義方法會有函式宣告提升,也就是函式的呼叫可以在函式宣告前

Python全棧學習筆記day 17:函式:二分法(老男孩Python全棧學習s9 day17 二分法程式有些問題)

遞迴函式 遞迴 : 在函式中呼叫自身函式 最大遞迴深度預設是997/998 —— 是python從記憶體角度出發做得限制 二分法: 實現程式: 最基礎版:(很多問題:切分導致出現了新列表,無法返回元素在 l 中的位置) l = [2,3,5,10,15,16,

python摸爬滾打day14----內建函式,函式

1、匿名函式  用一句話實現的簡單函式.   ret = lambda x : x ** 2      即 函式名 = lambda 形參 : 返回值   print(ret(5))  ----> 25 2、sorted()  ---->

用C語言探究函式的巧妙處(以斐波那契數列為例)

對於許多C語言的初學者來說,函式是一個比較重要的版塊.函式的使用不僅在學習程式設計的時期可以方便我們解決一些問題.它在未來的工作中也是程式設計師們經常運用的東西.而函式的遞迴是函式這一版塊比較難懂的東西.因此小編以輸出斐波那契數列的第N項為例,來探討函式的遞迴的應用給我們的程式碼帶來的方便.

Python路-Day07區域性變數與全域性變數,函式

區域性變數和全域性變數的含義 在子程式中定義的變數稱為區域性變數,在程式的一開始定義的變數稱為全域性變數. 全域性變數作用域是整個程式,區域性變數作用域是定義該變數的子程式. 當全域性變數於區域性變數同名時: 在定義區域性變數的子程式內,區域性變數起作用,在其它地方全域性變數起作用.

python函式,二分查詢

遞迴函式 遞迴函式一直都是我們所覺得難理解的以一種方式,但其實,也很好理解的,遞迴函式就是自己呼叫自己。就是在重複的做同一件事情。只是有的時候,也最好不要使用遞迴函式,因為你的函式一旦呼叫,就要開闢新的記憶體空間。不利於程式的執行。python對你記憶體一個保護機制,預設只能遞迴到998

python全棧開發匿名函式函式

python全棧開發,匿名函式,遞迴函式 匿名函式 lambda函式也叫匿名函式,即函式沒有具體的名稱。是為了解決一些功能很簡單需求而設計的一句話函式。如下: #這段程式碼defcalc(n):returnn**nprint(calc(10))#換成匿名函式calc =lambdan:n

golang 學習語言切片Slice Range範圍 MAP 函式

Go 語言切片是對陣列的抽象。 Go 陣列的長度不可改變,在特定場景中這樣的集合就不太適用,Go中提供了一種靈活,功能強悍的內建型別切片(“動態陣列”),與陣列相比切片的長度是不固定的,可以追加元素,在追加時可能使切片的容量增大。 定義一個未指定大小的切片

php函式簡單例項講解

遞迴函式即自呼叫函式,在函式體內部直接或者間接的自己呼叫自己,即函式的巢狀呼叫是函式本身。通常在此型別的函式提之中會附加一個條件判斷敘述,以判斷是否需要執行遞迴呼叫,並且在特定的條件下終止函式的遞迴呼叫動作,把目前流程的主控權交回到上一層函式來執行。以此,當某

python函式二分法查詢

函式的遞迴: 在一個函式的內部呼叫自己 死迴圈: 可以無限迴圈,不會停止 while True: print('我不是遞迴') 遞迴: 不是死迴圈,有最大迴圈深度 def story(): print('我是遞迴') story() story() 超過了遞迴的最大深度報錯

Python3---函式的作用域,閉包

一.函式的作用域全域性變數和區域性變數定義在函式內部的變數擁有一個區域性作用域,定義在函式外的擁有全域性作用域。(1)函式內部的變數,作用域只在函式內部,函式內部不可以直接更改函式外部的變數(2)函式內部如果需要改變全域性變數,就需要使用global修飾變數(3)在函式巢狀函

算法系列函式(七位數字)

七對數字 今有兩個1,兩個2,兩個3,...兩個7,把它們排成一行。 要求,兩個1間有1個其它數字,兩個2間有2個其它數字,以此類推,兩個7之間有7個其它數字。如下就是一個符合要求的排列: 17126425374635 當然,如果把它倒過來,也是符合要求的。 請你找出另一種符合要求的

第二週實驗報告編寫函式將十進位制數轉換成二進位制數輸出

  實驗目的:編寫遞迴函式將十進位制數轉換成二進位制數輸出 實驗內容: * 程式頭部註釋開始 * 程式的版權和版本宣告部分 * Copyright (c) 2011, 煙臺大學計算機學院學生 * Copyright (c) 2011, 煙臺大學計算機學院學生 * All r

函式的編寫思路注意事項

函式的巢狀  在呼叫一個A函式時,A函式又呼叫B函式,B函式又呼叫C函式,...   遞迴函式   就是直接或間接呼叫自己   可以簡便的方式解決複雜問題   速度比功能相同的非遞迴函式慢   遞迴必須是有條件的   // 遞迴函式求陣列元素的最大值   #include&

輸入一個十進位制整數,設計函式,將該整數轉化為一個二進位制數。 思考: 如何將一個十進位制數轉化成一個8進位制和16進位制數。

1,輸入一個十進位制整數,設計遞迴函式,將該整數轉化為一個二進位制數。思考: 如何將一個十進位制數轉化成一個8進位制和16進位制數。 #include<stdio.h> #define  N  20 int main() { int a,n,c,k,i; cha

python函式求n的階乘,優缺點次數設定

遞迴函式兩大特點: 1.能夠呼叫函式自身 2.至少有一個出口(結束函式自身呼叫) 函式實現: def calnum(num): if num != 1: # 遞迴呼叫自身

好程式設計師web前端分享函式作用域

作用域的生命週期。   var a = 10;   function m1(){  &nb

測開函式進階· 第1篇《函式

## 堅持原創輸出,點選藍字關注我吧 ![](https://gitee.com/qinghanstudy/qinghan/raw/master/img/20201220162312.png) 作者:清菡 部落格:oschina、雲+社群、知乎等各大平臺都有。 > 由於微信公眾號推送改為了資訊流的

十一、Go基礎程式設計:函式函式型別、匿名函式與閉包

1. 遞迴函式 遞迴指函式可以直接或間接的呼叫自身。 遞迴函式通常有相同的結構:一個跳出條件和一個遞迴體。所謂跳出條件就是根據傳入的引數判斷是否需要停止遞迴,而遞迴體則是函式自身所做的一些處理。 //通過迴圈實現1+2+3……+100 func Test01() int { i