首页 > 代码库 > Linux/Unix C编程之的perror函数,strerror函数,errno

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头文件中;

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

?

<assert.h>中支持assert()函数,注意,assert()检查发现条件不成立时调用abort()终止程序执行,应用程序没有机会做清除工作。assert的作用是现计算表达式 expression ,如果其值为假(即为0),那么它先向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

  1. //程序名:errtest.c,环境为linux??
  2. ???
  3. #include?<stdio.h>??
  4. #include?<stdlib.h>??
  5. #include?<string.h>??
  6. #include?<errno.h>??
  7. int?main(int?argc,char?*argv[]){??
  8. FILE?*fp;??
  9. char?*buf;??
  10. if((fp=fopen(argv[1],"r"))==NULL)??
  11. {??
  12. perror("perror");??
  13. printf("sterror:%s\n",strerror(errno));??
  14. exit(1);??
  15. }??
  16. perror("perror");??
  17. errno=13;??
  18. printf("strerror:%s\n",strerror(errno));??
  19. fclose(fp);??
  20. return?0;??
  21. }??
  22. ???
  23. 编译为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得到的一个信息)

?

?

?

?

?

?

?

?

?

?

?

?

关于errnoperror,strerror函数

errno是一个由POSIXISO C标准定义的符号,看(用)起来就好像是一个整形变量。当系统调用或库函数发生错误的时候,比如以只读方式打开一个不存在的文件时,它的值将会被改变,根据errno值的不同,我们就可以知道自己的程序发生了什么错误,然后进行相应的处理。有人说,函数不是可以返回值吗,根据返回值照样可以判断程序在哪里出错了,为什么还需要errno?如果你有这样的疑问,推荐你看下这篇文章

为什么,要强调errno看起来好像是一个整形变量呢?因为有的标准(ISO C)只规定了errno的作用,而没有规定它的实现方式,它可能被定义成一个变量,也有可能被定义成一个宏,这个具体要看编译器自己的实现。早些时候,POSIX.1曾把errno定义成extern int errno这种形式,但现在这种方式比较少见了。因为以这种形式来实现errno,在多线程环境下errno变量是被多个线程共享的,这样可能线程A发生某些错误改变了errno的值,线程B虽然没有发生任何错误,但是当它检测errno的值的时候,线程B会以为自己发生了错误。所以现在errnoLinux中被实现成extern int * __errno_location(void): #define errno (*__errno_location()),这样每个线程都有自己的errno,不会再发生混乱了。

?

perrorstrerror函数都是用来打印错误提示信息的,它们的原型分别是:

char *strerror(int errnum);

它返回errnum的值所对应的错误提示信息,例如errnum等于12的话,它就会返回"Cannot allocate memory"

void? perror(const char *s);

它先打印s指向的字符串,然后输出当前errno所对应的错误提示信息,例如当前errno若为12,调用perror("ABC"),会输出"ABC: Cannot allocate memory"

?

关于errno有三点需要特别注意:

1、如果系统调用或库函数正确执行的话,errno的值是不会被清零(置0,注意这里是不会被清零,不是不会被改变)的,假若执行函数A的时候发生了错误errno被改变,接下来直接执行函数B,如果函数B正确执行的话,errno还保留函数A发生错误时被设置的值。所以,在利用errno之前,最好先对函数的返回值进行判断,看是否发生了错误,返回值错误再利用errno判断时哪里发生了错误。所以如果一个函数无法从返回值上判断正误,而只能通过errno来判断出错,那你在调用它之前必须手动将errno清零

2、系统调用或库函数正确执行,并不保证errno的值不会被改变!

3、任何错误号(即发生错误时errno的取值)都是非0的。

综上所述,当需要用errno来判断函数是否正确执行的时候,最好先将errno清零,函数执行结束时,通过其返回值判断函数是否正确执行,若没有正确执行,再根据errno判断时哪里发生了错误。

?

?

?

?

perror函数和strerror函数的区别

首先简单说一下file descriptors(文件描述符)

????? file descriptor 0standard 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手册,

perror是将errno对应的错误消息的字符串打印到标准错误输出上,即stderr2上,若你的程序将标准错误输出重定向到/dev/null,那就看不到了,就不能用perror了。而 strerror的作用只是将errno对应的错误消息字符串返回,要怎样处理完全由你自己决定。通常我们选择把错误消息保存到日志文件中,即写文件,所以通常可以用fprintf(fp, "%s", strerror(errno))将错误消息打印到fp指向的文件中。其中perrorerrno对应的错误消息集合跟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

??

?

?

?

?

?

?

?

?

?

?

?

?

?

?

?

?

?

?

?

?

?

?

?

?

?

?

?

?

?

?

?

?

?

?

?

?

?

?

?

?

Linux/Unix C编程之的perror函数,strerror函数,errno