printf()
用换行符结束您的消息;这fflush()
仍然是一个好主意,因为您将要更改标准输出的位置,尽管如果程序的标准输出要发送到终端,通常不需要这样做。如果标准输出要发送到一个文件并且fflush()
没有到位,那么您将获得三个"Hello\n"
写入管道的副本。
当您将标准输出更改为管道时,您的消息确实会写入管道。
当您关闭写入文件描述符时,您不会遇到任何问题。然后,您将一秒钟写入Hello
管道。您需要它fflush()
来确保标准 I/O 包实际上已将其缓冲数据写入管道。
然后,您从管道中读取到output
缓冲区。您应该检查您读取的字节数,因为字符串不会以空值结尾。您应该读取 10 个字节(当消息中没有任何换行符时)。
PIPE:
然后,您再次使用前缀写入管道。
要修复,请将消息写入标准错误。
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int out_pipe[2];
char output[101];
if (pipe(out_pipe) != 0) {
perror("pipe()");
exit(1);
}
printf("Hello\n");
fflush(stdout);
dup2(out_pipe[1], STDOUT_FILENO);
printf("Hello\n");
fflush(stdout);
close(out_pipe[1]);
printf("Hello\n");
fflush(stdout);
int n = read(out_pipe[0], output, sizeof(output));
close(out_pipe[0]);
fprintf(stderr, "PIPE: %.*s\n", n, output);
return 0;
}
请注意,我将 的定义output
从一个数组更改char *
为一个简单的char
. 通过更改,我得到了输出:
$ ./pipe3
Hello
PIPE: Hello
Hello
$
那是因为我在写入管道的消息中以及以标准错误结尾的格式字符串中包含了换行符。
是否有可能“重新启用”标准输出?
是的; 只需在使用之前为标准输出保留原始文件描述符dup2()
的副本,然后在完成管道后恢复副本。
我删除了两个主要fflush()
调用,示例输出演示了终端和文件输出之间的区别:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int out_pipe[2];
char output[101];
int old_stdout;
if (pipe(out_pipe) != 0) {
perror("pipe()");
exit(1);
}
printf("Hello\n");
old_stdout = dup(STDOUT_FILENO);
dup2(out_pipe[1], STDOUT_FILENO);
printf("Hello\n");
close(out_pipe[1]);
printf("Hello\n");
fflush(stdout);
int n = read(out_pipe[0], output, sizeof(output));
close(out_pipe[0]);
dup2(old_stdout, STDOUT_FILENO);
printf("PIPE: %d <<%.*s>>\n", n, n, output);
return 0;
}
示例输出:
$ ./pipe3Hello
PIPE: 12 <<Hello
Hello
>>
$./pipe3 > output
'pipe3' is up to date.
$ cat output
PIPE: 18 <<Hello
Hello
Hello
>>
$
如果删除剩余fflush()
的 ,程序将挂起。管道中没有任何内容(因为标准 I/O 尚未刷新其缓冲区,因为它未满且输出不再是终端),但管道已打开以进行写入,因此内核认为该输入可能会出现在它上面——如果只有打开管道进行写入的程序没有在管道的读取端等待输入出现。程序本身陷入僵局。