目录

前言:

加深理解

stderr


前言:

本文是重定向和缓冲区的续篇,所以篇幅并不会很长。

本文的主要目标是介绍stderr,对于0 1 即stdin stdout默认打开我们是能够理解的,stderr是什么我们好像并没有使用过?并且本文会加深一下缓冲区的理解和重定向的理解。

那么话不多说,进入正题吧。


加深理解

我们通过一个函数,sprintf来介绍缓冲区,因为sprintf是C语言的函数,而在C语言里面这个函数我们基本上没有使用过,所以学习Linux也有一定程度上介绍了C语言的调用底层的函数。

sprintf的参数是str,后面是正常的printf的参数。

我们可以通过该函数往一个数组里面写入数据:

int main()
{
    myFILE *fp = my_fopen(FILE_NAME, "w");
    if(fp == NULL) return 1;

    const char *str = "hello bit";
    int cnt = 10;
    char buffer[128];
    while(cnt)
    {
        sprintf(buffer, "%s - %d", str, cnt);
        my_fwrite(fp, buffer, strlen(buffer)); // strlen()+1不需要
        cnt--;
        sleep(1);
        my_fflush(fp);
    }
    my_fclose(fp);
    return 0;
}

通过sprintf写入了数据之后,使用我们自己实现的fwrite函数,往fp文件指针指向的缓冲区进行写入,每写入一次,就sleep一秒,然后刷新缓冲区,这样的结果,是将fp指向的缓冲区写入动态的字符串:

这个过程是动态的,但是如果我们将fflush去掉,并且在buffer数组里面不写入\n,我们看到的结果就是log.txt里面是等程序运行完,也就是进程终止之后,强制刷新缓冲区,从而导致的数据刷新出来:

这个点从另一个点,告诉了我们用户级别,也就是语言层面的缓冲区的存在。

而使用函数fllush 转义字符\n都是可以刷新该缓冲区,数据刷新之后,由OS将将数据从内核级别的缓冲区刷新到磁盘里面去。

也算是简单的复习了一下,今天的重点是stderr。

由一个问题引出:

平时我们的使用都是stdin stdout偏多,对于stderr,我们只知道它和错误有关,那么具体的表现是什么呢?我们现在看看。


stderr

我们先使用C++的代码看看:

int main()
{
	cout << "Hello Linux! I am cout\n" << endl;
	cerr << "Hello Linux! I am cerr\n" << endl;
	return 0;
}

为什么这里的cout 和 cerr打印出来的都是一样的呢?

我们使用C语言的stderr stdout试试:

int main()
{
    fprintf(stdout,"Hello Linux! I am stdout\n");
    fprintf(stderr,"Hello Linux! I am stderr\n");
    return 0;
}

此时结果居然还是一样的,难道stderr和stdout就没有区别了吗?

并不是,我们试试重定向?

使用>的时候,发现stdout的数据,存放到了log.txt里面,但是stderr并没有,好像事情有点眉目了?

你想,当用户操作计算机的时候,对于数据的流动是不大清晰的,比如报错,比如输出,甚至比如输入的信息都需要计算机帮我们完成,那么借助谁帮我们完成呢?

其实靠的就是stdin stdout stderror,如果没有报错什么的,stdout stderr的用法基本上是一样的,但是如果有报错信息,我们无法将报错信息重定向到log.txt,这是因为>的真正名称叫做标准输出重定向符,也就是只重定向标准输出,对于标准错误是不会重定向的,所以如果有如下代码:

int main()
{
    fprintf(stdout,"Hello Linux! I am stdout\n");
    fprintf(stderr,"Hello Linux! I am stderr\n");
    fprintf(stderr,"Hello Linux! I am stderr\n");
    fprintf(stdout,"Hello Linux! I am stderr\n");
    fprintf(stdout,"Hello Linux! I am stderr\n");
    fprintf(stderr,"Hello Linux! I am stderr\n");
    fprintf(stderr,"Hello Linux! I am stderr\n");
    fprintf(stdout,"Hello Linux! I am stderr\n");
    fprintf(stderr,"Hello Linux! I am stderr\n");
    return 0;
}

也就是stdout stderr的信息混在了一起,人眼分辨出来肯定十分费力,所以使用标准输出重定向的时候,就可以分辨出来了:

对于标准错误就只能打印在显示器上,这个点从另一方面也验证了1 2对应的显示器其实是同一个的结果。

那么如果我想要将1 2的消息都重定向呢?我们就可以:

这个指令稍微有点怪异,但是解释起来是很容易的。进程运行的时候,1重定向到了log.txt里面,2>&1的意思是将1的内容拷贝到2里面,包括文件指针。所以相当于让2的文件指针也指向了1所指向的文件。

此时,完成了2的重定向。

那么,同学们有没有用过,perror呢!!为什么报错的时候我们使用这个打印,而不是使用printf打印!!这里也算是一个call back了,因为perror本质是给2打印,printf是给1打印,虽然结果一样,但是本质不同!!

这是对于stderr的理解。


感谢阅读!

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐