问题描述
我有一个简单的C文件,该文件使用printf
和write(1,..)
函数写入标准输出。
文件:main.c
#include<stdio.h>
#include<unistd.h>
int main()
{
printf("Hello\n");
printf("Mars\n");
fsync(1);
write(1,"Ola\n",4);
write(1,"Earth\n",6);
}
> gcc main.c -o test
当我将输出重定向到文件时,我看到的顺序与终端中输出的顺序不同。看来,当我使用重定向write(..)
之前要写printf(..)
时,甚至更困难的是,printf()
在代码中更早,并且在它们之间有fsync(..)
。 >
是否有重定向操作符的某些变体可以确保顺序,或者我做错了什么。
终端输出:
> ./test
Hello
Mars
Ola
Earth
在out
文件中输出:
> ./test >out
# or ./test|tee out
> cat out
Ola
Earth
Hello
Mars
解决方法
printf
写入C流stdout
,该流由C标准库例程缓冲,并最终写入Unix文件描述符1。
fsync
和write
在Unix文件描述符1上运行。fsync
从文件描述符1中清除数据,但对C标准库流的缓冲区没有影响。
C标准库I / O例程的运行方式有所不同,具体取决于标准输出是发送到终端还是文件。在程序启动过程中将检测到该错误。当输出将输出到终端时,将其传递给用户被认为是很重要的,并且在将\n
写入流时,将刷新缓冲区。这称为行缓冲,默认情况下,输出到终端的行设置为行缓冲。
当输出要发送到文件时,立即刷新该文件并不重要,因为不希望用户立即看到它,并且如果完全缓冲输出,性能会更好。因此,仅在缓冲区已满,关闭流或发出显式刷新请求时才刷新缓冲区。这称为完全缓冲,默认情况下,输出到文件的设置为完全缓冲。
这通常在C 2018 7.21.3中得到解决,其中第7段说:
…当且仅当可以确定该流不引用交互式设备时,标准输入流和标准输出流才被完全缓冲。
(当输出是终端时,C实现也可以使用 unbuffered 模式代替 line buffered ,在这种情况下,所有字符都将尽快发送到终端就像他们写的那样。这是不常见的。)
您可以显式请求使用stdout
刷新fflush(stdout)
。
打开stdout
之后但对其执行任何其他操作之前,可以使用setvbuf(stdout,NULL,mode,0)
更改其缓冲方法,其中mode
为_IOFBF
,{{1 }}或_IOLBF
分别用于全缓冲,行缓冲或无缓冲。 (您还可以传递_IONBF
数组及其大小来代替char
和NULL
,并且库将使用该数组作为缓冲区,在此之后,请勿将数组用于任何其他目的。如果您传递0
和一个大小,则库可能会使用该大小来执行自己的缓冲区分配,但这不能保证。)NULL
返回一个{如果不能满足请求,则为非零。
看看dup2系统调用:https://www.geeksforgeeks.org/dup-dup2-linux-system-call/
您可以将stdoutput / input重定向到文件