#include <stdio.h> // void perror(const char *msg);
#include <string.h> // char *strerror(int errnum);
#include <errno.h> //errno
errno 是错误代码,在 errno.h头文件中;
perror是错误输出函数,输出格式为:msg:errno对应的错误信息(加上一个换行符);
strerror 是通过参数 errnum (就是errno),返回对应的错误信息。
以下是测试程序:
--------------------------------------------------------------------
// p_str_error.c
// perror , strerror 函数 , errno 测试
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main(int argc, char *argv[])
{
FILE *fp;
char *buf;
if( (fp = fopen(argv[1], "r")) == NULL)
{
perror("perror"); // 好方便
errno = 12;
printf("strerror: %s\n", strerror(errno)); //转换错误码为对应的错误信息
exit(1);
}
perror("perror");
errno = 13;
printf("strerror: %s\n", strerror(errno));
fclose(fp);
return 0;
}
--------------------------------------------------------------------
输入一个存在的文件名,如:./a.out 111
open失败则会输出:
perror: No such file or directory
strerror: Cannot allocate memory
open成功则会输出:
perror: Success
strerror: Permission denied
很明显,perror信息是由 perror函数输出的了,第二行是 strerror通过将 errno 轮换成对应的错误信息打印出来。
这次就写这么多了,程序简单,没啥好说的了。
最近在搭建开发环境,设计整个系统架构了。花了六年时间研发的系统,终于上线了。
我要用多少时间来学习呢,还好有资料,有源码,学习起来还不算吃力,嘿嘿。。。。。。
我要写一套山寨版的^_^!!!
<stdio.h>中定义了perror(),perror是在标准输出上输出msg字符串,然后再后面加上:错误语段(这个错误语段对应这时的errno)
<string.h>中定义了strerror(),strerror是把一个错误numb作为参数,然后返回错误numb所对应的错误语段,一般用errno。
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <errno.h>
int main(int argc, char* argv[])
{
int i=open("/usr/src/s.t",0);
perror(argv[0]);
printf(strerror(errno));
return 0;
}
执行结果:
]$./test
./test: No such file or directory
No such file or directory
),那么它先向stderr打印一条出错信息,然后通过调用 abort 来终止程序运行。
C标准定义了__LINE__和__FILE__宏,GNU C扩展中定义了__FUNCTION__宏,可以用来实现代码跟踪调试。这是三个非常有用的全局变量,当程序需要输出一些内容,而又想知道输出的内容是在哪里输出的时候,这几个全局变量就派上用场了。__FILE__,__FUNCTION__, __LINE__ 从名字可以直接看出来了,对应的:代码文件名, 函数名, 行号。
<errno.h>中定义了errno,注意没有函数会将errno清零,所以在调用可能设置errno的函数之前先将errno清零。但是errno是一个数字,代表的具体含义还要到errno.h中去阅读宏定义,而每次查阅是一件很繁琐的事情。所以经常char *strerror(int errno)将错误代码转换为字符串错误信息,可以将该字符串和其它的信息组合输出到用户界面。
<stdlib.h>中定义了abort()、exit()和atexit()函数。
函数abort()将导致程序异常终止,在终止前程序没有机会执行atexit()登记的函数,也没有计划执行一些常规的清除工作。同时,abort()还会产生core dump,如果没有ulimit限制的话。
函数exit()和abort()类似,但它在完成清理工作之后才终止程序。
函数atexit()登记在程序正常终止时要调用的函数。
<syslog.h>中定义了syslogd的接口,常用于系统日志。
Linux/Unix C编程之的perror函数,strerror函数,errno
#include <stdio.h> // void perror(const char *msg);
#include <string.h> // char *strerror(int errnum);
#include <errno.h> //errno
errno是错误代码,在errno.h头文件中
void perror(const char *s)
perror是错误输出函数,在标准输出设备上输出一个错误信息。
参数s一般是参数错误的函数
例如perror("fun"),其输出为:fun:后面跟着错误信息(加上一个换行符)
char *strerror(int errnum);通过参数errnum(也就是errno),返回错误信息
以下是测试程序:
[cpp] view plaincopy
- //程序名:errtest.c,环境为linux
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <errno.h>
- int main(int argc,char *argv[]){
- FILE *fp;
- char *buf;
- if((fp=fopen(argv[1],"r"))==NULL)
- {
- perror("perror");
- printf("sterror:%s\n",strerror(errno));
- exit(1);
- }
- perror("perror");
- errno=13;
- printf("strerror:%s\n",strerror(errno));
- fclose(fp);
- return 0;
- }
- 编译为errtest
如果输入这样的命令格式:./errtest 111.c(其中111.c不存在)
输出为:
perror: No such file or directory
sterror:Illegal seek
就是两个都是输出到屏幕上来了。而且sterror函数通过errno得到错误代码
如果命令格式为:./errtest 111.c > out.c(其中111.c不存在)
把输出重定位到out.c文件中,会发现屏幕输出为:
perror: No such file or directory
就是说函数perror始终输出到标准输出设备上。而printf输出到文件中了
如果命令格式为:./errtest 222.c(其中222.c存在)
屏幕输出为:
perror: Success
strerror: Permission denied(通过errno=12得到的一个信息)
errno是一个由POSIX和ISO C标准定义的符号,看(用)起来就好像是一个整形变量。当系统调用或库函数发生错误的时候,比如以只读方式打开一个不存在的文件时,它的值将会被改变,根据errno值的不同,我们就可以知道自己的程序发生了什么错误,然后进行相应的处理。有人说,函数不是可以返回值吗,根据返回值照样可以判断程序在哪里出错了,为什么还需要errno?如果你有这样的疑问,推荐你看下这篇文章。
为什么,要强调errno看起来好像是一个整形变量呢?因为有的标准(如ISO C)只规定了errno的作用,而没有规定它的实现方式,它可能被定义成一个变量,也有可能被定义成一个宏,这个具体要看编译器自己的实现。早些时候,POSIX.1曾把errno定义成extern int errno这种形式,但现在这种方式比较少见了。因为以这种形式来实现errno,在多线程环境下errno变量是被多个线程共享的,这样可能线程A发生某些错误改变了errno的值,线程B虽然没有发生任何错误,但是当它检测errno的值的时候,线程B会以为自己发生了错误。所以现在errno在Linux中被实现成extern int * __errno_location(void): #define errno (*__errno_location()),这样每个线程都有自己的errno,不会再发生混乱了。
perror和strerror函数都是用来打印错误提示信息的,它们的原型分别是:
char *strerror(int errnum);
的话,它就会返回"Cannot allocate memory"。
void perror(const char *s);
,调用perror("ABC"),会输出"ABC: Cannot allocate memory"。
关于errno有三点需要特别注意:
、如果系统调用或库函数正确执行的话,errno的值是,注意这里是不会被清零,不是不会被改变)的,假若执行函数A的时候发生了错误errno被改变,接下来直接执行函数B,如果函数B正确执行的话,errno还保留函数A发生错误时被设置的值。所以,在利用errno之前,最好先对函数的返回值进行判断,看是否发生了错误,返回值错误再利用errno判断时哪里发生了错误。所以如果一个函数无法从返回值上判断正误,而只能通过errno来判断出错,那你在调用它之前必须手动将errno清零!
、系统调用或库函数正确执行,并不保证errno的值不会被改变!
、任何错误号(即发生错误时errno的取值)都是非0的。
综上所述,当需要用errno来判断函数是否正确执行的时候,最好先将errno清零,函数执行结束时,通过其返回值判断函数是否正确执行,若没有正确执行,再根据errno判断时哪里发生了错误。
首先简单说一下file descriptors(文件描述符):
file descriptor 0是standard input (stdin标准输入)
file descriptor 1 是 standard output (stdout标准输出)
file descriptor 2 是 standard error output(stderr标准错误输出)
perror()原型:
#include <stdio.h>
void perror(const char *msg);
它是基于errno的当前值,在标准出错上产生一条出错信息,然后返回。它首先输出由msg指向的字符串,然后是一个冒号,一个空格,接着是对应于errno值的出错信息,最后是一个换行符。
strerror()原型:
#include <string.h>
char * strerror(int errnum);
此函数将errnum(它通常就说errno值)映射为一个出错信息字符串,并返回此字符串的指针。
区别:
查看man手册,
上,若你的程序将标准错误输出重定向到/dev/null,那就看不到了,就不能用perror了。而 strerror的作用只是将errno对应的错误消息字符串返回,要怎样处理完全由你自己决定。通常我们选择把错误消息保存到日志文件中,即写文件,所以通常可以用fprintf(fp, "%s", strerror(errno))将错误消息打印到fp指向的文件中。其中perror中errno对应的错误消息集合跟strerror是一样的,也就是说不会漏掉某些错误。
可以通过一个程序示例下:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
int main(int argc,char *argv[])
{
FILE * fp;
if((fp = fopen(argv[1],"r"))==NULL)
{
perror("perror");
printf("fork error:%s\n",strerror(errno));
exit(1);
}
perror("perror");
printf("fork error:%s\n",strerror(errno));
return
0;
}
运行测试如下:
zjf@zjf:~/work/code/procise/application/chapter_1$ ./a.out
perror: Bad address
fork error:Bad address
zjf@zjf:~/work/code/procise/application/chapter_1$ ./a.out
2> file
fork error:Invalid argument