1. linux下用dup2關閉標準輸出后,使用printf列印資訊的問題。
2. 代碼如下:
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
int main()
{
int fd1=open("eup.txt", O_RDWR | O_CREAT | O_TRUNC, 0644);
if(fd1==-1){
printf("#LINE %d:",__LINE__);
perror("open");
return -1;
}
//printf("Hello, World!\n");//不加這句,eup.txt中沒內容。
int fd2=dup2(fd1,1);
if(fd2==-1){
printf("#LINE %d:",__LINE__);
perror("open");
return -1;
}
printf("fd1:%d\nfd2:%d\nfd3:%d\n",fd1,fd2,3);
close(fd2);
close(fd1);
return 0;
}
3.問題為:將printf("Hello, World!\n");這句話注釋掉,運行程式后eup.txt里面
沒有任何內容,這個是正確的。但取消注釋后,運行程式,發現eup.txt里面
有如下內容:
fd1:4
fd2:1
fd3:3
這是為什么?哪個函式讓重繪了檔案緩沖區??
首先\n不能重繪檔案緩沖區的。如果是close函式重繪的,為什么注釋printf("Hello, World!\n");
這句話時運行程式后沒有將內容重繪到 eup.txt檔案中??
哪位大神知道??
uj5u.com熱心網友回復:
cplusplus forum里的應該也是你吧,不知道你是從哪里看的這個問題,有點厲害。因為這個問題,學習了一些函式,感謝!
close()并不能重繪緩沖區,這個在man close里有明確講到,并且也提到使用fsync;但是fsync對tty無效,所以也不行。
經過嘗試,有3種方法可以寫入eup.txt。
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#define METHOD 1
int main()
{
#if METHOD == 1
setvbuf(stdout, NULL, _IONBF, 0);
#endif
int fd1=open("eup.txt", O_RDWR | O_CREAT | O_TRUNC, 0644);
if(fd1==-1){
printf("#LINE %d:",__LINE__);
perror("open");
return -1;
}
/* printf("Hello, World!\n"); */
int fd2=dup2(fd1,1);
if(fd2==-1){
printf("#LINE %d:",__LINE__);
perror("open");
return -1;
}
printf("fd1:%d\nfd2:%d\nfd3:%d\n",fd1,fd2,3);
#if METHOD == 2
char buf[200] = {0};
sprintf(buf, "fd1:%d\nfd2:%d\nfd3:%d\n",fd1,fd2,3);
write(fileno(stdout), buf, strlen(buf)+1);
#endif
#if METHOD == 3
fclose(stdout);
#endif
close(fd2);
close(fd1);
return 0;
}
1. 把stdout改成無緩沖,說明和緩沖方式有很大關系吧(?)
2. 用write
3. close(fd2) -> fclose(stdout),fclose為何神奇,看了一下glibc/libio/iofclose.c里面_IO_new_fclose的原始碼,表示看不懂...
綜上,這個問題與Linux/Unix系統內核可能更相關;常用標準C庫函式。
uj5u.com熱心網友回復:
是我問的。我就是想知道在不注釋 printf("Hello, World!\n"); 的前提下運行程式,為什么 printf("fd1:%d\nfd2:%d\nfd3:%d\n",fd1,fd2,3); 能夠把內容寫入eup.txt 。后來看了一些資料說:printf向終端或者螢屏輸出時是行緩沖(\n 可以刷緩沖區),向檔案輸出時是全緩沖(緩沖區滿列印,一般緩沖區不是幾個字符能充滿的)。
注釋掉 printf("Hello, World!\n"); 后,由于 int fd2=dup2(fd1,1); 使得標準輸出重定向到檔案,printf是全緩沖,所以printf("fd1:%d\nfd2:%d\nfd3:%d\n",fd1,fd2,3); 中 \n 并不能刷緩沖區,資料只是在緩沖區,并沒有寫入檔案里。
不注釋 printf("Hello, World!\n"); ,即使后面呼叫了 int fd2=dup2(fd1,1); printf還是行緩沖,并沒有變為全緩沖(原因我也不知道,只是聽別人說的)。所以 printf("fd1:%d\nfd2:%d\nfd3:%d\n",fd1,fd2,3); 中 \n 能刷緩沖區,資料寫入了檔案里。
uj5u.com熱心網友回復:
Good!我順著你的思路找到了這篇內容 -> 前往stackoverflow你應該也能看明白,我還是說一下我的理解。
無論是C/C++,它的輸入輸出函式并不會負責line-buffered還是full-buffered,這個由輸出的檔案屬性來決定;
如果是interactive device,那么就是line-buffered;
否則,就是full-buffered。
但是C/C++怎么判斷輸出檔案的屬性呢?文中也說了,不同的實作盡管不同,但差不多都是用stat();
并且一旦決定了一種快取方式,后面就不會改變了(除非顯式的setvbuf())
所以,先printf的時候,C已經明確它的輸出stdout導向terminal tty,所以使用line-buffered的方式,
但后來用dup2()重定向,但這對于C來說是不知道的,依然用line-buffered的方式重繪它的快取區。
然而一開始就把stdout重定向到file的話,C是可以了解到這一資訊并改變成full-buffered的方式。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/14478.html
標籤:應用程序開發區
