這篇是上星期的上課內容,我又拖了超過一個禮拜
因為不知為何這次上課速度非常快,教的東西又很雜
而我又很懶(毆)
不過不能再拖了,因為我現在能做的也只有讀書了

===
ch 10 除錯(Debugging)
===


《錯誤的種類》
Specification errors - 模型錯誤(如漏掉變數)
design error - 設計錯誤(沒有做好規劃)
coding error - 程式錯誤(寫程式寫錯了)
  -> dry running - 把所有組合放進去測試

我們這次要來學習使用electric fence來除錯

一般應該要先打upd更新軟體清單
不過因為這套軟體幾乎都不更新
所以可以直接輸入ins electric-fence安裝
(記得安裝軟體要先切換root權限)

11-01.gif

‧debug1
執行完卻發現什麼東西都沒有顯示,不知道他有沒有錯
輸入diff debug1.c debug2.c比較一下兩個範例
原來debug2多了顯示出來的程式碼

 11-02.gif

‧debug2
顯示了sort完的結果,不過答案是錯的...
因為系統一次給你一個block

11-03.gif

‧debug3
比較一下就知道,差別在data直接給他4k記憶體


《修改系統語言為英文》

輸入以下指令
export LC_ALL='POSIX' - 全部改成POSIX
export LANG="C"
輸入locale看設定有沒有被改掉吧

11-04.gif

《Debug相關語法》

‧DEBUG mode才做
#ifdef DEBUG#endif將程式包起來

#ifdef DEBUG
printf(“variable x has value = %d\n”, x);
#endif

‧程式執行時給他debug值(1~7)
#define BASIC_DEBUG 1
#define EXTRA_DEBUG 2
#define SUPER_DEBUG 4 - 超詳細的錯誤內容

#if (DEBUG & EXTRA_DEBUG) //如果是Extra Debug才顯示
printf...
#endif

‧如果沒有debug值就給他0
#ifndef DEBUG
#define DEBUG 0
#endif


‧如果覺得每次修改完都要重新compile很麻煩
改成這樣即可
if (debug) {
    sprintf(msg, ...)
    write_debug(msg)
}


記得編譯時加上-DDEBUG參數,才是真的在DEBUG喔

《用gdb來Debug》
Segmentation fault是記憶體配置問題,通常發生在pointer身上
輸入gdb debug3開始偵錯

以下是在gdb模式下的指令
help - 顯示所有說明
註:用Ctrl+L可將畫面消掉

11-05.gif

run - 開始執行程式,發現第23行有問題

11-06.gif

backtrace - 查看函數呼叫堆疊
print j - 顯示變數j內容

11-07.gif

print a[$-1].key - $指的是上一次最後的值

11-08.gif

list - 把目前中斷的點放在中間
再輸入list會繼續往下看
list 10 - 把第十行放在中間

11-09.gif

quit - 離開

問題出在 j=4
printf a[4]  正確
printf a[5]  錯誤
所以問題出在5超過範圍(原來是超基本的錯誤...)

‧debug4
可以顯示但是結果還是錯了

break 20 - 設中斷點停在第20行
print a[0]@5 - 顯示陣列下五個內容

11-10.gif

display a[0]@5 - 每次碰到中斷點就做後面的事
cont - 繼續執行

還不懂的話可以輸入info displayinfo break查看說明

11-11.gif

寫了這麼多,請讓我說句中肯的話,一句就好
以上都是怪胎用的,深受古代程式餘毒

現在都21世紀了,誰還會慢慢輸入中斷點用這種方式debug啊
請改用CodeBlock(其實我比較喜歡輕巧的dev-c++)

《用CodeBlock來Debug》

先開啟empty專案

11-12.gif

開啟完後,在專案上按右鍵選擇Add files...
增加ch10/debug4.c這個檔案

11-13.gif

並請在Debug跟Release的按鈕上打勾再按OK

11-14.gif

先編譯,然後在21行設定中斷點(行號上按一下出現紅點即可)

選擇功能表的[debug]-[debuggubg windows]-[watch]
開啟Debug視窗,可以看變數內容
選擇[debug]-[start]來用debug模式執行

不過因為那時候老師也是弄的2266...所以也弄不出什麼好的東西
我放棄用CodeBlock來偵錯了...orz

《其他Debug工具》

‧Lint
會詳細跟你說程式可能會有什麼問題

ins splint - 安裝lint
splint debug3.c - 執行方式

11-15.gif

‧ctags
產生原始碼每個tag(函數或變數名)的所在位置
執行後會產生tags這個檔案,可參考每一個tag的資訊
不過好像只支援vim這個編輯器...

apt-cache search ctags - 如果你不知道ctags的安裝名稱,請先搜尋
ins exuberant-ctags - 安裝ctags

11-16.gif

ctags *.c - 目錄下產生一個tags檔案
cat tags - 看其內容

老實說我覺得不是很好用...

11-17.gif

‧chref
其實我不知道他是要幹嘛的,老師沒有說清楚
好像跟上面那個程式差不多

dpkg-reconfigure cxref - 第一次執行請先讓他自動設定
cxref *.c - 執行

‧cflow
分析你的程式,看程式那個地方花多少時間

gcc -pg -o debug4 debug4.c - 編譯
./debug4 - 執行程式後目錄下會產生gmon.out
gprof debug4 gmon.out -p - 產生統計表
gprof debug4 gmon.out -q - 產生相關聯的呼叫

11-18.gif

《其他範例教學》

‧assert
原始碼內有一段
assert(x >= 0.0);
代表x沒達成>=0的條件就會印出訊息

編譯時多加Don't debug
gcc -o assert -DNDEBUG assert.c -lm
assert部分就不會執行,不用把assert砍掉

11-19.gif

‧efence
gcc -o efence efence.c
./efence

不會顯示任何問題,但其實有問題

gcc -o efence efence.c -lefence
./efence

改用此行編譯再執行就會發現問題

11-20.gif

‧checker
去執行也看似沒問題
apt-get install valgrind
valgrind --leak-check=yes -v ./checker

應該就會出現問題了(我懶的試了=__=)


===
ch 11 程序(Process)
===


ps - 可以顯示目前的東西
pstree - 樹狀顯示
pstree -p - 加上process id

11-21.gif

ps -lls -l一樣會顯示很多資訊
ps -ef - 會發現所有程式都是由init產生的
他是所有程式的祖先

ps aux - 目前所有process的狀態是什麼

11-22.gif

oclock & - 執行oclock這個程式
nice oclock & - 加了nice代表讓他在背景執行


diff system1.c system2.c
system1跟system2差別只在一個會等他跑完一個不會罷了

11-23.gif

system1加上以下幾行
    int pid;
    pid = getpid();
    printf("My pid=%d\n",pid);

執行時有看到process id,程式執行完就沒了

11-24.gif

‧pexec
一樣加上以下幾行,但printf那一行在前頭跟後面都加上來測試
    int pid;
    pid = getpid();
    printf("My pid=%d\n",pid);

執行後卻發現最後那個printf沒有顯示出來
因為pexec會把自己的process蓋掉
所以後面的成事都做不到了

11-25.gif

‧fork
簡單講就是把自己一分為二(複製一份自己),下次上課有較詳細的內容


三個禮拜之後要交作業
其實作業最簡單的話只要寫三行就好
char cmd[256];
gets(cmd);
system(cmd);

不過老師規定不可以用system要用fork
請搜尋man execman forkman dup查看說明

arrow
arrow
    全站熱搜

    蕭雲 發表在 痞客邦 留言(2) 人氣()