原文:Exercise 4: Introducing Valgrindhtml
譯者:飛龍git
如今是介紹另外一個工具的時間了,在你學習C的過程當中,你會時時刻刻用到它,它就是 Valgrind
。我如今就向你介紹 Valgrind
,是由於從如今開始你將會在「如何使它崩潰」一節中用到它。Valgrind
是一個運行你的程序的程序,而且隨後會報告全部你犯下的可怕錯誤。它是一款至關棒的自由軟件,我在編寫C代碼時一直使用它。github
回憶一下在上一章中,我讓你移除printf
的一個參數,來是你的代碼崩潰。它打印出了一些奇怪的結果,但我病欸有告訴你爲何他會這樣打印。這個練習中咱們要使用Valgrind
來搞清楚爲何。curl
注函數
這本書前面的幾章在講解一小段代碼的東西,摻雜了一些必要的工具,它們在本書的剩餘章節會用到。這樣作的緣由是,閱讀這本書的大多數人都不熟悉編譯語言,也必然不熟悉自動化的輔助工具。經過先讓你懂得如何使用
make
和Valgrind
,我能夠在後面使用它們更快地教你C語言,以及幫助你儘早找出全部的bug。工具這一章以後我就再也不介紹更多的工具了,每章的內容大部分是代碼,以及少許的語法。然而,我也會說起少許工具,咱們能夠用它來真正瞭解發生了什麼,以及更好地瞭解常見的錯誤和問題。學習
你能夠用OS上的包管理器來安裝Valgrind
,可是我想讓你學習如何從源碼安裝程序。這涉及到下面幾個步驟:this
下載源碼的歸檔文件來得到源碼url
解壓歸檔文件,將文件提取到你的電腦上code
運行./configure
來創建構建所需的配置
運行make
來構建源碼,就像以前所作的那樣
運行sudo make install
來將它安裝到你的電腦
下面是執行以上步驟的腳本,我想讓你複製它:
# 1) Download it (use wget if you don't have curl) curl -O http://valgrind.org/downloads/valgrind-3.6.1.tar.bz2 # use md5sum to make sure it matches the one on the site md5sum valgrind-3.6.1.tar.bz2 # 2) Unpack it. tar -xjvf valgrind-3.6.1.tar.bz2 # cd into the newly created directory cd valgrind-3.6.1 # 3) configure it ./configure # 4) make it make # 5) install it (need root) sudo make install
按照這份腳本,可是若是 Valgrind
有新的版本請更新它。若是它不能正常執行,也請試着深刻研究緣由。
使用 Valgrind
十分簡單,只要執行valgrind theprogram
,它就會運行你的程序,隨後打印出你的程序運行時出現的全部錯誤。在這個練習中,咱們會崩潰在一個錯誤輸出上,而後會修復它。
首先,這裏有一個ex3.c
的故意出錯的版本,叫作ex4.c
。出於練習目的,將它再次輸入到文件中:
#include <stdio.h> /* Warning: This program is wrong on purpose. */ int main() { int age = 10; int height; printf("I am %d years old.\n"); printf("I am %d inches tall.\n", height); return 0; }
你會發現,除了兩個經典的錯誤外,其他部分都相同:
沒有初始化height
變量
沒有將age
變量傳入第一個printf
函數
如今咱們像一般同樣構建它,可是不要直接運行,而是使用Valgrind
來運行它(見源碼:"使用Valgrind構建並運行 ex4.c"):
$ make ex4 cc -Wall -g ex4.c -o ex4 ex4.c: In function 'main': ex4.c:10: warning: too few arguments for format ex4.c:7: warning: unused variable 'age' ex4.c:11: warning: 'height' is used uninitialized in this function $ valgrind ./ex4 ==3082== Memcheck, a memory error detector ==3082== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al. ==3082== Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for copyright info ==3082== Command: ./ex4 ==3082== I am -16775432 years old. ==3082== Use of uninitialised value of size 8 ==3082== at 0x4E730EB: _itoa_word (_itoa.c:195) ==3082== by 0x4E743D8: vfprintf (vfprintf.c:1613) ==3082== by 0x4E7E6F9: printf (printf.c:35) ==3082== by 0x40052B: main (ex4.c:11) ==3082== ==3082== Conditional jump or move depends on uninitialised value(s) ==3082== at 0x4E730F5: _itoa_word (_itoa.c:195) ==3082== by 0x4E743D8: vfprintf (vfprintf.c:1613) ==3082== by 0x4E7E6F9: printf (printf.c:35) ==3082== by 0x40052B: main (ex4.c:11) ==3082== ==3082== Conditional jump or move depends on uninitialised value(s) ==3082== at 0x4E7633B: vfprintf (vfprintf.c:1613) ==3082== by 0x4E7E6F9: printf (printf.c:35) ==3082== by 0x40052B: main (ex4.c:11) ==3082== ==3082== Conditional jump or move depends on uninitialised value(s) ==3082== at 0x4E744C6: vfprintf (vfprintf.c:1613) ==3082== by 0x4E7E6F9: printf (printf.c:35) ==3082== by 0x40052B: main (ex4.c:11) ==3082== I am 0 inches tall. ==3082== ==3082== HEAP SUMMARY: ==3082== in use at exit: 0 bytes in 0 blocks ==3082== total heap usage: 0 allocs, 0 frees, 0 bytes allocated ==3082== ==3082== All heap blocks were freed -- no leaks are possible ==3082== ==3082== For counts of detected and suppressed errors, rerun with: -v ==3082== Use --track-origins=yes to see where uninitialised values come from ==3082== ERROR SUMMARY: 4 errors from 4 contexts (suppressed: 4 from 4) $
注
若是你運行了
Valgrind
,它顯示一些相似於by 0x4052112: (below main) (libc-start.c:226)
的東西,而不是main.c
中的行號,你須要使用valgrind --track-origins=yes ./ex4
命令來運行你的Valgrind
。因爲某些緣由,valgrind
的Debian和Ubuntu上的版本會這樣,可是其它的不會。
上面那段輸出很是長,由於Valgrind
在明確地告訴你程序中的每一個錯誤都在哪兒。讓咱們從開頭逐行分析一下(行號在左邊,你能夠參照):
1
你執行了一般的make ex4
來構建它。確保你看到的cc
命令和它同樣,而且帶有-g
選項,不然Valgrind
的輸出不會帶上行號。
2~6
要注意編譯器也會向你報告源碼的錯誤,它警告你「向格式化函數傳入了過少的變量」,由於你忘記包含age
變量。
7
而後使用valgrind ./ex4
來運行程序。
8
以後Valgrind
變得十分奇怪,並向你報錯:
14~18
在main (ex4.c:11)
(意思是文件ex4.c
的main
函數的第11行)的那行中,有「大小爲8的未初始化的值」。你經過查看錯誤找到了它,而且在它下面看到了「棧蹤影」。最開始看到的那行(ex4.c:11)
在最下面,若是你不明白哪裏出錯了,你能夠向上看,好比printf.c:35
。一般最下面的一行最重要(這個例子中是第18行)。
20~24
下一個錯誤位於 main
函數中的 ex4.c:11
。Valgrind
不喜歡這一行,它說的是一些 if 語句或者 while 循環基於一個未初始化的值,在這個例子中是height
。
25~35
剩下的錯誤都大同小異,由於這個值還在繼續使用。
37~46
最後程序退出了,Valgrind
顯示出一份摘要,告訴你程序有多爛。
這段信息讀起來會至關多,下面是你的處理方法:
不管何時你運行C程序而且使它工做,都應該使用Valgrind
從新運行它來檢查。
對於獲得的每一個錯誤,找到「源碼:行數」提示的位置,而後修復它。你能夠上網搜索錯誤信息,來弄清楚它的意思。
一旦你的程序在Valgrind
下不出現任何錯誤信息,應該就行了。你可能學會了如何編寫代碼的一些技巧。
在這個練習中我並不期待你立刻徹底掌握Valgrind
,可是你應該安裝而且學會如何快速使用它,以便咱們將它用於後面的練習。
按照上面的指導,使用Valgrind
和編譯器修復這個程序。
在互聯網上查詢Valgrind
相關的資料。
下載另外一個程序並手動構建它。嘗試一些你已經使用,但歷來沒有手動構建的程序。
看看Valgrind
的源碼是如何在目錄下組織的,而且閱讀它的Makefile文件。不要擔憂,這對我來講沒有任何意義。