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));