笨辦法學C 練習4:Valgrind 介紹

練習4:Valgrind 介紹

原文:Exercise 4: Introducing Valgrindhtml

譯者:飛龍git

如今是介紹另外一個工具的時間了,在你學習C的過程當中,你會時時刻刻用到它,它就是 Valgrind。我如今就向你介紹 Valgrind,是由於從如今開始你將會在「如何使它崩潰」一節中用到它。Valgrind是一個運行你的程序的程序,而且隨後會報告全部你犯下的可怕錯誤。它是一款至關棒的自由軟件,我在編寫C代碼時一直使用它。github

回憶一下在上一章中,我讓你移除printf的一個參數,來是你的代碼崩潰。它打印出了一些奇怪的結果,但我病欸有告訴你爲何他會這樣打印。這個練習中咱們要使用Valgrind來搞清楚爲何。curl

函數

這本書前面的幾章在講解一小段代碼的東西,摻雜了一些必要的工具,它們在本書的剩餘章節會用到。這樣作的緣由是,閱讀這本書的大多數人都不熟悉編譯語言,也必然不熟悉自動化的輔助工具。經過先讓你懂得如何使用makeValgrind,我能夠在後面使用它們更快地教你C語言,以及幫助你儘早找出全部的bug。工具

這一章以後我就再也不介紹更多的工具了,每章的內容大部分是代碼,以及少許的語法。然而,我也會說起少許工具,咱們能夠用它來真正瞭解發生了什麼,以及更好地瞭解常見的錯誤和問題。學習

安裝 Valgrind

你能夠用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 十分簡單,只要執行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.cmain函數的第11行)的那行中,有「大小爲8的未初始化的值」。你經過查看錯誤找到了它,而且在它下面看到了「棧蹤影」。最開始看到的那行(ex4.c:11)在最下面,若是你不明白哪裏出錯了,你能夠向上看,好比printf.c:35。一般最下面的一行最重要(這個例子中是第18行)。

  20~24

  下一個錯誤位於 main 函數中的 ex4.c:11Valgrind不喜歡這一行,它說的是一些 if 語句或者 while 循環基於一個未初始化的值,在這個例子中是height

  25~35

  剩下的錯誤都大同小異,由於這個值還在繼續使用。

37~46

最後程序退出了,Valgrind顯示出一份摘要,告訴你程序有多爛。

這段信息讀起來會至關多,下面是你的處理方法:

  • 不管何時你運行C程序而且使它工做,都應該使用Valgrind從新運行它來檢查。

  • 對於獲得的每一個錯誤,找到「源碼:行數」提示的位置,而後修復它。你能夠上網搜索錯誤信息,來弄清楚它的意思。

  • 一旦你的程序在Valgrind下不出現任何錯誤信息,應該就行了。你可能學會了如何編寫代碼的一些技巧。

在這個練習中我並不期待你立刻徹底掌握Valgrind,可是你應該安裝而且學會如何快速使用它,以便咱們將它用於後面的練習。

附加題

  • 按照上面的指導,使用Valgrind和編譯器修復這個程序。

  • 在互聯網上查詢Valgrind相關的資料。

  • 下載另外一個程序並手動構建它。嘗試一些你已經使用,但歷來沒有手動構建的程序。

  • 看看Valgrind的源碼是如何在目錄下組織的,而且閱讀它的Makefile文件。不要擔憂,這對我來講沒有任何意義。

相關文章
相關標籤/搜索