1. 程式人生 > >嵌入式除錯printf重定向到檔案

嵌入式除錯printf重定向到檔案

 除了人工的分析之外,最簡單最直接的除錯方法要算printf了。不過,我們這裡推薦使用的並不是初學C語言時使用的函式int printf(const char *format, ...),而是稍微複雜一點的fprintf()函式,因為它更方便我們之後重定向錯誤輸出資訊到指定的裝置。fprintf()函式的原型如下:
int fprintf(FILE *stream, const char *format, ...)
可以看到,它與printf()函式相比多出來了第一個引數FILE *stream,其意義是將列印的內容輸出到檔案流指標stream指向的流。所謂流,通常是指程式輸入或輸出的一個連續的位元組序列,裝置(例如滑鼠、鍵盤、磁碟、螢幕、調變解調器和印表機)的輸入和輸出都是用流來處理的,在C語言中,所有的流均以檔案的形式出現——不一定是物理磁碟檔案,還可以是對應於某個輸入/輸出源的邏輯檔案。C語言提供了5種標準的流,你的程式在任何時候都可以使用它們,並且不必開啟或關閉它們。以下列出了這5種標準的流。
------------------------------------------------
    名稱          描 述             例 子
------------------------------------------------
    stdin        標準輸入           鍵盤
    stdout       標準輸出             螢幕
    stderr       標準錯誤            螢幕
    stdprn       標準印表機          LPT1埠
    stdaux       標準序列裝置       COM1埠
------------------------------------------------
    其中,stdprn和stdaux並不總是預先定義好的,因為LPT1和COM1埠在某些作業系統中是沒有意義的,而stdin,stdout 和stderr總是預先定義好的。此外,stdin並不一定來自鍵盤,stdout也並不一定顯示在螢幕上,它們都可以重定向到磁碟檔案或其它裝置上。我們在標頭檔案stdio.h中可以找到stdin,stdout 和stderr的定義如下:
/* Standard streams. */extern struct _IO_FILE *stdin;      /* Standard input stream. */
extern struct _IO_FILE *stdout;     /* Standard output stream. */extern struct _IO_FILE *stderr;     /* Standard error output stream. */
在使用fprintf()函式時,通常我們可以將第一個引數設為stdout或者stderr,打印出錯除錯資訊的時候則推薦使用stderr而不是stdout,這是一種慣例,同時也由於核心在處理stdout和stderr時的優先順序不一樣,後者的優先順序要高一些,因此有時候如果程式異常退出時,stderr能得到輸出,而stdout就不行。printf(...) 實際上相當於fprintf(stdout, ...),這也是為什麼我們不推薦使用它的原因。在輸出除錯資訊的時候,我們推薦使用fprintf(stderr, …),或者使用某個指定的檔案流fprintf(some_stream, …)。那麼具體如何在必要的時候重定向
fprintf()中的除錯資訊呢?來看看下面的一些方法:當除錯資訊的量比較大,需要一些時間或者其他輔助工具來搜尋過濾時,僅僅利用顯示螢幕來輸出除錯資訊是不夠的,這時我們經常將這些資訊輸出到所謂的日誌檔案(log)中,之後再仔細的分析log檔案來發現問題。Ø 利用ShellI/O重定向簡單的寫log方法可以通過shell的I/O重定向機制來實現,比如下面的程式碼:

     1 #include <stdio.h>

     2     3 int main()     4 {     5      fprintf(stdout, "This is a standard output info!\n");
     6      fprintf(stderr, "This is a standard error output info!\n");     7      return 0;     8 }
在預設條件下,編譯執行的結果是列印資訊都輸出在螢幕上:

$ gcc fprint.c -o fprint

$ ./fprintThis is a standard output info!This is a standard error output info!
這是因為預設情況下,shell所開啟的stdout和stderr裝置都是顯示螢幕。不過我們可以通過shell的重定向功能來將列印資訊寫到檔案中去。比如:

$ ./fprint >output.log

This is a standard error output info!$ cat output.logThis is a standard output info!
這樣,我們把stdout的輸出寫到了檔案output.log中,不過stderr的輸出還是在螢幕上。如何重定向stderr呢?這需要用到shell定義的檔案描述符。在shell下stdin, stdout, 和stderr的檔案描述符分別是0, 1和2,我們可以用下面的方法重定向:

$ ./fprint >output.log 2>error.log

$ cat output.logThis is a standard output info!$ cat error.logThis is a standard error output info!$$ ./fprint >output.log 2>&1$ cat output.logThis is a standard error output info!This is a standard output info!
其中./fprint >output.log 2>error.log分別將stdout和stderr的輸出寫入到檔案output.log和error.log中,而./fprint >output.log 2>&1則表示將stderr的輸出追加到stdout的檔案output.log中(結果是output.log中既有stdout輸出也有stderr輸出)。一些常用的shell I/O語法如下:cmd > file  把 stdout 重定向到 file 檔案中
cmd >> file  把 stdout 重定向到 file 檔案中(追加)
cmd 1> fiel  把 stdout 重定向到 file 檔案中
cmd > file 2>&1  把 stdout 和 stderr 一起重定向到 file 檔案中
cmd 2> file  把 stderr 重定向到 file 檔案中
cmd 2>> file  把 stderr 重定向到 file 檔案中(追加)
cmd >> file 2>&1  把 stderr 和 stderr 一起重定向到 file 檔案中(追加)在平時的簡單除錯中,我們可以靈活利用這些方法來快速得到log檔案。Ø freopen()進行重定向有時候我們要求在程式中能夠控制標準流的重定向,這時可以利用標準C庫函式freopen()。freopen()的函式原型如下:

FILE *freopen(const char *filename, const char *mode, FILE *stream)

下面的程式碼用來測試用函式freopen()重定向stderr:

     1 #include <stdio.h>

     2     3 int main()     4 {     5      if (freopen("err.log", "w", stderr)==NULL)     6          fprintf(stderr, "error redirecting stderr\n");     7      fprintf(stdout, "This is a standard output info!\n");     8      fprintf(stderr, "This is a standard error output info!\n");     9      fclose(stderr);    10      return 0;    11 }
在第5行我們用freopen()函式將stderr重定向到了”err.log”檔案,這樣得到的結果如下:

$ gcc print_log.c -o print_log

$ ./print_logThis is a standard output info!$ cat err.logThis is a standard error output info!
可見第8行列印到stderr的資訊被重定向到了err.log檔案中,而第7stdout的列印資訊則還是輸出到了螢幕上