C 标准数据流在重定向后更改顺序?

C 标准数据流在重定向后更改顺序?,c,io-redirection,C,Io Redirection,这些天我在学习“apue”,一个典型案例的结果让我困惑。以下是“样本c”的样本代码: #包括“apue.h” #包括 #定义BUFF_SZ 4096 int main() { int n=0; 字符buff[buff_SZ]={'\0'}; 而((n=read(STDIN_FILENO,buff,buff_SZ))>0){ printf(“读取%d字节\n”,n); if(写入(标准输出文件号,buff,n)!=n){ err_sys(“写入错误”); } } if(noutfile,则使用ca

这些天我在学习“apue”,一个典型案例的结果让我困惑。以下是“样本c”的样本代码:

#包括“apue.h”
#包括
#定义BUFF_SZ 4096
int main()
{
int n=0;
字符buff[buff_SZ]={'\0'};
而((n=read(STDIN_FILENO,buff,buff_SZ))>0){
printf(“读取%d字节\n”,n);
if(写入(标准输出文件号,buff,n)!=n){
err_sys(“写入错误”);
}
}
if(n<0){
错误系统(“读取错误”);
}
返回0;
}
编译
gcc sample.c
后,您可以使用此命令
echo Hello |/a.out
在终端上获得以下std输出:

读取6个字节
您好

但是,如果将输出重定向到文件
echo Hello |/a.out>outfile
,则使用
cat outfile
查看内容:

您好
读取6个字节


重定向后输出更改顺序!不知是否有人能告诉我原因?

对于标准I/O函数
printf
,当您输出到终端时,默认情况下,标准输出是行缓冲的

printf("read %d bytes\n", n);
\n
此处导致输出刷新

但是,当您输出到文件时,默认情况下它是完全缓冲的。除非缓冲区已满,否则输出不会刷新,或者您显式刷新它


另一方面,低级系统调用
write
,是无缓冲的

printf("read %d bytes\n", n);
通常,不建议将标准I/O调用与系统调用混合使用。

printf()
,默认情况下,缓冲其输出,而
write()
不缓冲,两者之间不同步

因此,在您的代码中,
printf()
可能将其数据存储在缓冲区中并返回,然后调用
write()
,当
main()
返回时,
printf()
s缓冲区被刷新,从而显示缓冲输出。根据您的描述,在重定向输出时会发生这种情况

也可能是
printf()
立即写入数据,然后调用
write()
。根据您的描述,当输出未重定向时会发生这种情况

通常,流重定向的一个部分是更改缓冲区,从而更改缓冲时的行为,例如
stdout
stdin
。精确的更改取决于正在发生的重定向类型(例如文件、管道、不同的显示设备等)


假设
printf()
将数据写入缓冲区,并在刷新该缓冲区时使用
write()
生成输出。这意味着
write()
的所有公开调用都将立即生成其输出,但缓冲的数据可能会打印出错误的顺序。

问题在于写入操作是由
write(2)
调用处理的,因此您实际上会失去对所发生情况的控制。 如果我们查看文档中的,我们可以看到,在
read()
发生之前,不能保证实际写入。更具体地说:

A successful return from write() does not make any guarantee that data has 
been committed to disk. In fact, on some buggy implementations, it does not even 
guarantee that space has successfully been reserved for the data. The only way to 
be sure is to call fsync(2) after you are done writing all your data. 

这意味着,根据
写入(2)
的实现和缓冲(即使在重定向和打印到屏幕之间也可能不同),您可以得到不同的结果。

不要在同一文件上混合使用stdio和POSIX读/写。结果将是不可预测的,因为你刚刚发现了艰难的道路。如果一定要这样做,每次从stdio切换到posix再切换回来时都会刷新。此引用与观察到的结果无关。我们可以从中得出结论,根据系统调用的实现,写操作不一定以相同的方式处理,也不一定以正确的顺序处理。您错了。这句话没有这么说<代码>写如果结果不按顺序发送,那比没有用还糟糕。为什么有人会想到具体说明这样一件事?这句话所说的是当你调用
write
,它返回,然后你的操作系统崩溃或计算机关闭时的情况。在这种情况下,您的数据不能保证保存在磁盘上。此外,在时间T处写入的数据可能会在磁盘上结束,而在时间T-1处写入的数据可能不会结束。事实并非如此。重复,不是两个数据块都在磁盘上,而是在文件中顺序颠倒。