嵌入式除錯printf重定向到檔案
阿新 • • 發佈:2019-02-13
除了人工的分析之外,最簡單最直接的除錯方法要算printf了。不過,我們這裡推薦使用的並不是初學C語言時使用的函式int printf(const char *format, ...),而是稍微複雜一點的fprintf()函式,因為它更方便我們之後重定向錯誤輸出資訊到指定的裝置。fprintf()函式的原型如下:
可以看到,它與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的定義如下:
在使用fprintf()函式時,通常我們可以將第一個引數設為stdout或者stderr,打印出錯除錯資訊的時候則推薦使用stderr而不是stdout,這是一種慣例,同時也由於核心在處理stdout和stderr時的優先順序不一樣,後者的優先順序要高一些,因此有時候如果程式異常退出時,stderr能得到輸出,而stdout就不行。printf(...) 實際上相當於fprintf(stdout, ...),這也是為什麼我們不推薦使用它的原因。在輸出除錯資訊的時候,我們推薦使用fprintf(stderr, …),或者使用某個指定的檔案流fprintf(some_stream, …)。那麼具體如何在必要的時候重定向 fprintf()中的除錯資訊呢?來看看下面的一些方法:當除錯資訊的量比較大,需要一些時間或者其他輔助工具來搜尋過濾時,僅僅利用顯示螢幕來輸出除錯資訊是不夠的,這時我們經常將這些資訊輸出到所謂的日誌檔案(log)中,之後再仔細的分析log檔案來發現問題。Ø 利用Shell的I/O重定向簡單的寫log方法可以通過shell的I/O重定向機制來實現,比如下面的程式碼:
在預設條件下,編譯執行的結果是列印資訊都輸出在螢幕上:
這是因為預設情況下,shell所開啟的stdout和stderr裝置都是顯示螢幕。不過我們可以通過shell的重定向功能來將列印資訊寫到檔案中去。比如:
這樣,我們把stdout的輸出寫到了檔案output.log中,不過stderr的輸出還是在螢幕上。如何重定向stderr呢?這需要用到shell定義的檔案描述符。在shell下stdin, stdout, 和stderr的檔案描述符分別是0, 1和2,我們可以用下面的方法重定向:
其中./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()的函式原型如下:
下面的程式碼用來測試用函式freopen()重定向stderr:
在第5行我們用freopen()函式將stderr重定向到了”err.log”檔案,這樣得到的結果如下:
可見第8行列印到stderr的資訊被重定向到了err.log檔案中,而第7行stdout的列印資訊則還是輸出到了螢幕上
int fprintf(FILE *stream, const char *format, ...) |
------------------------------------------------
名稱 描 述 例 子
------------------------------------------------
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. */ |
1 #include <stdio.h> 2 3 int main() 4 { 5 fprintf(stdout, "This is a standard output info!\n"); |
$ gcc fprint.c -o fprint $ ./fprintThis is a standard output info!This is a standard error output info! |
$ ./fprint >output.log This is a standard error output info!$ cat output.logThis is a standard output info! |
$ ./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! |
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) |
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 } |
$ gcc print_log.c -o print_log $ ./print_logThis is a standard output info!$ cat err.logThis is a standard error output info! |