errno可以理解为一个全局变量,它存储了出错信息。在下面三个路径可以看到errno相关的内容
/usr/include/errno.h
/usr/include/asm-generic/errno-base.h
/usr/include/asm-generic/errno.h
我们可以在这些文件中自己定义一些errno,这样可以做到我们自己知道原始错误信息,而打印出来给用户看的是我们希望用户看到的对原始错误的解释。
#include <string.h>
char *strerror(int errnum);
#include <unistd.h>
int dup(int oldfd);
int dup2(int oldfd, int newfd);
#define _GNU_SOURCE
#include <unistd.h>
int dup3(int oldfd, int newfd, int flags);
示例:一句话打印两次,先打入文件,后打至屏幕
/************************************************************
>File Name : dup_test.c
>Author : QQ
>Company : QQ
>Create Time: 2022年05月17日 星期二 16时09分41秒
************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
int main(int argc, char* argv[])
{
if(argc < 2)
{
printf("not found string\n");
return -1;
}
/*每开启一个进程,默认打开 0 1 2 三个文件描述符*/
/*首先备份标准输出*/
int stdoutfd = dup(STDOUT_FILENO);
/*打开一个文件*/
int fd = open("hello.txt", O_WRONLY | O_CREAT, 0644);
/*重定向标准输出1至文件*/
dup2(fd, STDOUT_FILENO);
printf("first: %s\n", argv[1]);
/* ===========================
printf会进行系统调用,需要刷新buffer
===========================
fflush(stdout);
*/
/*恢复标准输出*/
dup2(stdoutfd, STDOUT_FILENO);
printf("second: %s\n", argv[1]);
close(fd);
return 0;
}
我们编译运行一下,你会发现两次都打印在了屏幕上,其实这就是我们在《系统API与C库函数的调用关系》中讲的系统调用问题,C库函数printf()会调用系统API函数write(),这是会用到一个文件指针,这里面有一个缓冲区buffer,要打印的内容会先放入到buffer中,如果我们在第一次调用printf()函数后不刷新这个buffer缓冲区的话,在第二次打印的时候,buffer就会保留有上次调用时放入缓冲区的内容,所以打印到标准输出时,打印了两句话。
注意:这里的 "hello\ linux" 中,"\ " 使通过转义符把空格的特殊含义去掉,如果不加转义符,shell会把空格分开的内容当作两个字符串,通过转义符就可以实现在字符串中写入空格,这是shell的知识。
解决方法就是在第二次打印前刷新一下缓冲区,将上面代码中的fflush()函数放出即可