`stdio` 如何识别输出是重定向到终端还是磁盘文件?

`stdio` 如何识别输出是重定向到终端还是磁盘文件?
#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-bufferedstdio使用行缓冲对于stdoutie,当发现换行符时,'\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_IFREGs_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 

相关内容