Linux perror函数详解——错误信息输出利器 (linux perror())

Linux系统作为一款高性能、高稳定性的操作系统,其应用广泛,特别是在服务器领域。在使用Linux时,经常会出现各种错误,如网络连接错误、文件读写错误等。为了诊断并解决这些错误,Linux提供了众多的工具和函数,其中perror函数就是其中一个错误信息输出利器。

一、perror函数概述

perror函数是一个错误信息输出函数,其主要作用是将errno对应的错误信息输出到标准错误输出中(stderr)。该函数的原型如下:

“`C

#include

void perror(const char *s);

“`

perror函数只需要一个参数s,表示输出错误信息时的前缀字符,通常为程序名或相关信息。

二、perror函数使用示例

以下是一个使用perror函数的示例代码:

“`C

#include

#include

int mn()

{

FILE *fp;

char *filename = “not_exist.txt”;

fp = fopen(filename, “r”);

if (fp == NULL)

{

perror(“fopen error”);

printf(“errno=%d\n”, errno);

return 1;

}

fclose(fp);

return 0;

}

“`

上述代码中,我们尝试以只读方式打开一个不存在的文件,这会导致fopen函数返回一个空指针。在判断文件打开是否成功之后,我们调用了perror函数输出了错误信息。由于文件不存在,因此errno的值被设置为ENOENT,perror函数会将对应的错误信息输出到stderr中。执行该代码,输出结果如下:

“`

fopen error: No such file or directory

errno=2

“`

可以看到,perror函数输出了对应的错误信息“No such file or directory”,并且打印了errno的值为2,这正是ENOENT的值。

三、perror函数与errno变量

perror函数和errno变量是紧密相关的,errno变量定义在errno.h头文件中,其主要作用是存储最近一次系统调用发生错误时的错误码。每个错误码对应一个宏定义,例如ENOENT表示文件不存在,EACCES表示权限不足等。

通过perror函数,我们可以根据errno的值输出对应的错误信息,方便定位并解决错误。在使用perror函数时,需要先include errno.h头文件,以便正确使用errno变量。

四、perror函数源代码分析

perror函数的源代码实现如下:

“`C

#include “stdio_impl.h”

void perror(const char *msg)

{

int e = errno, oldtype;

__pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldtype);

__stdio_flockfile(stderr);

if (msg && *msg)

__stdio_fputs(msg, stderr);

__stdio_fputs(“: “, stderr);

__stdio_fputs(strerror(e), stderr);

__stdio_putc(‘\n’, stderr);

__stdio_funlockfile(stderr);

__pthread_setcancelstate(oldtype, 0);

}

“`

可以看到,perror函数主要分为以下几个步骤:

1. 获取当前errno的值;

2. 禁用线程取消;

3. 对标准错误流(stderr)加锁,以避免多线程中的输出混乱;

4. 如果msg不为空,则将其作为前缀输出到stderr中;

5. 输出errno对应的错误信息;

6. 输出换行符;

7. 解锁标准错误流;

8. 恢复线程取消状态。

通过分析源代码,我们可以了解到perror函数的实现原理,并且可以更好地理解其使用方法。

五、

相关问题拓展阅读:

linux关于管道说法错误的是什么

Linux关于管道 原创

:22:41

Gaodes

码龄5年

关注

管道的概念

管道是Unix中枣镇蔽最古老的进程间通信的形式。 我们把从一个进程连接到另一个进程的一个数据流称为一个“管道” 我们通常把是把一个进程的输出连接或“管接”(经过管道来连接)到另一个进程的输入。

管道特点

管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道 只能用于父子进程或者兄弟进程之间(具有亲凳州缘关系的进程)进行通信;通常,一个管道由一个进程创建,然后该进程调用fork,此后父、子进程之间就可应用该管道。

pipe函数

包含头文件 功能:创建一无名管道 原型

int pipe(int file_descriptor);

参数 file_descriptor:文件描述符数组,其中file_descriptor表示读端,file_descriptor表示写端 返回值:成功返回0,失败返回错误代码

示例代码:

#include

#include

#include

#include

#include

int main(int argc,char *argv)

{

int fd;

printf(“f=%d,f=%d\n”,fd,fd);

pipe(fd);

printf(“f=%d,f=%d\n”,fd,fd);

char buf={0};

int fid = fork();

if(fid > 0)

{

read(fd,buf,1024);

printf(“read data %s\n”,buf);

}

else if(fid == 0)

{

write(fd,”helloworld”,strlen(“helloworld”));

}

else

{

perror(“fork error”);

}

return 0;

}

打印结果

管道读写规则:如果试图从管道写端旅塌读取数据,或者向管道读端写入数据都将导致错误发生 当没有数据可读时,read调用就会阻塞,即进程暂停执行,一直等到有数据来到为止。 如果管道的另一端已经被关闭,也就是没有进程打开这个管道并向它写数据时,read调用就会阻塞

复制文件描述符dup

#include

#include

#include

#include

int main()

{

int fd = dup(1);

printf(“file fd= %d\n”,fd);

write(fd,”helloworld”,strlen(“helloworld”));

return 0;

}

打印结果:

1为输入到终端

shell管道的实现

原理通过把发的fd写复制到shell的1(标准输入),fd复制到shell的2(标准输出)

以下是代码:

#include

#include

#include

#include

#include

#include

int main()

{

int fd;

char buf ={0};

pipe(fd);

int pid = fork();

if(pid > 0)

{

read(fd,buf,1024);

printf(buf);

}

else if(pid == 0)

{

dup2(fd,1);

close(fd);

close(fd);

execlp(“ls”,”ls”,”-al”,NULL);

}

else

{

}

return 0;

}

实现结果:

popen函数

作用:允许一个程序把另外一个程序当作一个新的进程来启动,并能对它发送数据或接收数据

FILE* popen(const char *command, const char *open_mode);

command:待运行程序的名字和相应的参数 open_mode:必须是“r”或“w” 如果操作失败,popen会返回一个空指针

以下代码:

#include

#include

#include

#include

#include

#include

int main()

{

FILE *file = popen(“ls -al”,”r”);

char buf = {0};

fread(buf,1,1024,file);

fclose(file);

FILE *wcfile = popen(“wc”,”w”);

fwrite(buf,1,strlen(buf),wcfile);

fclose(wcfile);

return 0;

}

代码结果:

命名管道破裂测试

我们首先要知道命名管道,要读段和写段同时开启,才能向文件读写数据。

贴上代码来理解命名管道的规则

首先是读端:

#include

#include

#include

#include

#include

#include

int main(int argc,char *argv)

{

printf(“open before\n”);

int fd = open(“/home/gao/tmp/fifo”,O_RDON);

printf(“open after\n”);

//休眠5秒,读端退出

sleep(5);

return 0;

}

接下来是写端:

#include

#include

#include

#include

#include

#include

void handle(int signo)

{

printf(“cat signale = %d\n”,signo);

}

int main(int argc,char *argv)

{

signal(SIGPIPE,handle);

printf(“open before\n”);

int fd = open(“/home/gao/tmp/fifo”,O_WRON);

printf(“open after\n”);

//命名管道规则,如果写入读断被中断,写入会返回-1,并且管道会破裂,产生信号(SIGPIPE)

while(1)

{

int wrsize = write(fd,”helloworld”,strlen(“helloworld”));

printf(“size data:%d\n”,wrsize);

sleep(1);

}

}

执行写端:

它在等待另一端的开启,才能向里面写入数据

此时我们开启读端:

马上可以看到写段可以写数据

而执行5秒后,我们可以看到写的时候返回-1,并且获取到管道破裂的信息(SIGPIPE)

linux perror()的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于linux perror(),Linux perror函数详解——错误信息输出利器,linux关于管道说法错误的是什么的信息别忘了在本站进行查找喔。


数据运维技术 » Linux perror函数详解——错误信息输出利器 (linux perror())