stdio是否在关闭文件时将文件描述符偏移回到下一个未读位置?

问题描述

根据Linux程序员手册,在调用fork之后,父进程和子进程共享打开的文件描述符和文件偏移。

另一方面,已知glibc的stdio实现缓冲。因此,对scanf调用会导致文件偏移(读取)移动得远大于返回给最终用户的字节数,其余数据将存储在缓冲区中,以备下次调用

但是当我执行以下操作时会发生什么:

  1. 致电fork。现在,父母和孩子共享stdin
  2. 在子进程中调用scanf认情况下,stdin被块缓冲,所以scanf读取块。
  3. 检查子文件中的文件偏移量。
  4. 从子进程中退出
  5. 在父进程中等待子进程。
  6. 检查父级stdin中的文件偏移量。

根据glibc manual,当main返回时,

所有打开的流均已正确关闭

并在结束时

所有缓冲输入被丢弃

因此,我希望父母的stdin文件偏移量位于孩子的scanf停止读取(实际上停止读取)的位置。但是我将父级的stdin文件偏移移回到返回给用户的输入结束位置。

我通过手册和互联网进行搜索,但没有发现任何描述此行为的信息。是否已指定?

这是我的代码

#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>

int main() {
    int fd = fileno(stdin);
    printf("Begin pos: %ld\n",lseek(fd,SEEK_CUR));
    pid_t pid = fork();

    if (pid == 0) {
        char buffer[4096] = {};
        int readed = scanf("%s",buffer);
        printf("Child readed: %d,pos: %ld\n",readed,SEEK_CUR));
        return 0;
    }

    int status = 0;
    wait(&status);
    printf("Parrent pos: %ld\n",SEEK_CUR));

    return 0;
}

此处输出

> echo "aaa bbb ccc" > test
> ./a.out < test
Begin pos: 0
Child readed: 1,pos: 12
Parrent pos: 3

解决方法

观察到的行为符合fclose函数的POSIX要求:

如果该文件尚未在EOF上并且可以搜索,则如果流是基础文件的活动句柄,则应将基础打开文件描述的文件偏移设置为流的文件位置。文件说明。