結束您printf()
消息用換行; fflush()
仍然是一個好主意,因爲您即將更改標準輸出的位置,但如果程序的標準輸出傳送到終端通常不是必需的。如果標準輸出正在進行文件處理,並且fflush()
未到位,那麼您將得到三份"Hello\n"
寫入管道的副本。
當您將標準輸出更改爲管道時,您的消息確實被寫入管道。
關閉寫入文件描述符時,不會遇到任何問題。然後你寫第二個Hello
到管道。您需要這個fflush()
以確保標準I/O包實際上已將其緩衝數據寫入管道。
然後您從管道讀入緩衝區output
。您應該檢查您讀取的字節數,因爲字符串不會以null結尾。您應該讀取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並沒有刷新其緩衝區,因爲它不是完整的,輸出不是終端更多),但管道是對寫開放,所以內核認爲輸入可能會出現在它上面—如果只有管道打開的程序未在管道的讀取端等待輸入顯示。該計劃本身已陷入僵局。
是啊,這工作。是否有可能「重新啓用」stdout?其實我試圖在使用ncurses的時候存儲一些stdout消息(它會忽略這些消息,因爲它使用stdout本身)。所以我想把這些消息發送給一個字符串,然後用'stradd()'將它們發佈到ncurses。 – Aufziehvogel
我剛想到的一個想法是分叉,然後等待stdout和管道回到原始程序。我認爲這應該起作用,因爲原始線程仍然具有標準輸出,不是嗎?在那裏,我可以從管道的讀端讀取它。 – Aufziehvogel
如果你使用'fork()',你有兩個進程(每個進程只有一個控制線程),而不是你的註釋所暗示的一個進程中的兩個線程。是的,您可以在創建管道之後進行分叉,讓子進行I/O重定向並將管道中的信息寫入父級,然後讓父級讀取該數據並使用它。謹慎對待詛咒,雖然—,它聽起來很可疑,好像你可能會給它半無法消化的數據來顯示,這可能破壞它對屏幕上什麼位置的理解。 –