1. 程式人生 > >C++程式中列印錯誤資訊和標準錯誤流stderr

C++程式中列印錯誤資訊和標準錯誤流stderr

C++一共有三個標準流,分別是標準輸入(stdin)、輸出(stdout)、錯誤流(stderr

標準流定義和標頭檔案

FILE *stdin; 
FILE *stdout; 
FILE *stderr; 
#include <stdio.h>

C++為這三個標準流分別定義了指標,stdin、stdout、stderr,它們是常量指標(因此不能被賦值),使用者可以將他們作為引數用於諸如fprintf、getchar、putchar等函式中。

一般來說,stdin可以把鍵盤、磁碟檔案以及其他外設中的資料輸入記憶體,stdout則是把記憶體中的資料輸出到螢幕、磁碟檔案及其他外設。預設情況下,標準輸入裝置是鍵盤,而標準輸出和錯誤流是螢幕。

列印(函式)的錯誤資訊

除錯程式的時候,經常會有列印資訊到螢幕的需要,可以利用stderr和一些其他庫函式做到。這裡還要提到兩個函式:perror、strerror,還有一個全域性變數errno。

perror的定義如下:

void perror(
   const char *string
);

例如可以這樣使用:

FILE *fp;
if((fp = fopen("test.txt", "r")) == NULL)//以只讀的方式開啟test.txt
{
	perror("test.txt open error");
	exit(0);
}
如果工程目錄下沒有test.txt,那麼輸出如下:

test.txt open error: No such file or directory.

MSDN:The perror function prints an error message to stderr. 所以perror其實是將錯誤資訊傳遞給stderr,由stderr列印到螢幕上的。

擴寫上面的例子,來看看errno和strerror怎麼用:

FILE *fp;
if((fp = fopen("test.txt", "r")) == NULL)
{
	perror("test.txt open error");
	printf("%s\n",strerror(errno));
	printf("%d\n",errno);
	exit(0);
}

output:

test.txt open error: No such file or directory
No such file or directory
2

errno是一個int型的全域性變數,它(編碼成錯誤編號)返回函式的錯誤資訊(C/C++的庫函式大都是有返回值的,以便呼叫者知道該函式的執行結果),例如上例的錯誤資訊:2,所以直接列印errno對使用者(程式語言的使用者當然是程式設計師了)來說很不直觀。因此C++提供了strerror函式,它可以將errno的錯誤翻譯成對應的字串,例如上例中的No such file or directory,這樣可讀性就高了很多。

strerror的定義在string.h中:

char *strerror(
     int errnum
);
因此如果想知道errno的各個編號分別都代表什麼錯誤,可以將strerror的引數改成int型的數字,例如這樣輸出
printf("%s\n",strerror(2));

還有一個常用於輸出錯誤的函式是fprintf,它定義在stdio.h中:

//Print formatted data to a stream.
int fprintf( 
     FILE *stream,
     const char *format [,
     argument ]...
  );
它的作用是將格式化的資料定向到對應的流。

例如可以這樣使用:

fprintf(stderr,"error:%s\n",strerror(errno));

這樣其實就是把錯誤資訊定向到stderr標準流,再由stderr列印到螢幕(如果沒有對stderr做過重定向)。

總結完列印錯誤資訊的方法,來說說今天犯的一個很蠢的錯誤,因為自定義型別而出錯的典型例子,結構體Vertex定義如下:

typedef struct Vertex{
	struct Vertex *prev, *next;
	double coord[3];
}*VERTEX;

我在某個類的成員函式中定義並返回了一個VERTEX型別的值,函式中是這樣定義的:

VERTEX v = (VERTEX)malloc(sizeof(VERTEX));

然後在main函式中也用了一個VERTEX的變數vertex接收函式的返回值,接著,就出現了錯誤,而且很奇怪的是F5(啟動除錯)不出錯,CTRL+F5(執行不除錯)出現了錯誤(程式結束執行,典型的記憶體使用錯誤),莫名其妙看了很久都沒發現錯誤。

原因是什麼呢?為VERTEX v分配空間的寫法錯誤,上面的寫法等價於(struct Vertex*)malloc(sizeof(struct Vertex*)); sizeof的變數寫成了指標,這樣分配的空間只是一個指標的空間大小,也就是地址長度,32位的話就是4個位元組,而Vertex結構體的大小是不止4位元組的,於是在將函式返回值賦值給vertex時,CTRL+F5出錯,要使F5也出錯很簡單,去訪問vertex->next和vertex->coord[i],這樣就訪問了未被分配的空間。正確的寫法應該是:

VERTEX v = (struct Vertex*)malloc(sizeof(struct Vertex));
//等價於:
VERTEX v = (VERTEX)malloc(sizeof(struct Vertex));