![`stdio` 如何识别输出是重定向到终端还是磁盘文件?](https://linux22.com/image/213104/%60stdio%60%20%E5%A6%82%E4%BD%95%E8%AF%86%E5%88%AB%E8%BE%93%E5%87%BA%E6%98%AF%E9%87%8D%E5%AE%9A%E5%90%91%E5%88%B0%E7%BB%88%E7%AB%AF%E8%BF%98%E6%98%AF%E7%A3%81%E7%9B%98%E6%96%87%E4%BB%B6%EF%BC%9F%20.png)
#include <stdio.h>
#include <unistd.h>
int main(void)
{
printf("If I had more time, \n");
write(STDOUT_FILENO, "I would have written you a shorter letter.\n", 43);
return 0;
}
我读到了
I/O 处理函数(
stdio
库函数)和系统调用执行缓冲操作以提高性能。该函数在用户空间printf(3)
使用缓冲区。stdio
内核还缓冲 I/O,这样就不必在每次系统调用时都写入磁盘。默认情况下,当输出文件是终端时,使用该printf(3)
函数的 写入line-buffered
与stdio
使用行缓冲对于stdout
ie,当发现换行符时,'\n'
缓冲将刷新到缓冲区高速缓存。然而,当不是终端时,即标准输出被重定向到磁盘文件,只有当缓冲区没有更多空间(或文件流关闭)时才会刷新内容。如果上面程序的标准输出是终端,那么第一次调用printf
会将其缓冲区刷新到内核缓冲区(缓冲区高速缓存)当它找到换行符时'\n'
,输出的顺序将与上述语句中的顺序相同。但是,如果输出重定向到磁盘文件,则缓冲区stdio
将不会被刷新,并且系统调用的内容write(2)
将首先到达内核缓冲区,导致其在调用内容之前被刷新到磁盘printf
。
什么时候stdout
有终端
If I had more time,
I would have written you a shorter letter.
stdout
磁盘文件是什么时候
I would have written you a shorter letter.
If I had more time,
但我的问题是如何stdio library functions
知道是stdout
定向到终端还是磁盘文件?
答案1
printf
(我的特定 libc)在内部newfstatat()
对 stdout 文件描述符(即 1)执行系统调用。
如果它是您要输入的常规文件,或者它是字符设备(如伪终端),内核将填充这些st_mode
字段。S_IFREG
s_IFCHR
我是如何发现的:
gcc -o foo foo.c # compile your program
strace -o file.strace ./foo > tempfile
strace -o term.strace ./foo
diff *.strace #and look for things towards the end that concern the 1 file descriptor