标准I/O之实现细节

在UNIX系统中,标准I/O库最终都要调用文件I/O(read、write等)。每个标准I/O流都有一个与其相关联的文件描述符,可以对一个流调用fileno函数以获得其描述符。

注意,fileno不是ISO C标准部分,而是POSIX.1支持的扩展。

#include <stdio.h>
int fileno( FILE *fp );
返回值:与该流相关联的文件描述符

如果要调用dup或fcntl等函数,则需要此函数。

为了了解你所使用的系统中标准I/O库的实现,最好从头文件<stdio.h>开始。从中可以看到:FILE对象是如何定义的、每个流标志的定义以及定义为宏的各个标准I/O例程(例如getc)。

程序清单5-3中的程序为三个标准流以及一个普通文件相关联的流打印有关缓冲的状态信息。

程序清单5-3 对各个标准I/O流打印缓冲状态信息

[root@localhost apue]# cat prog5-3.c
#include "apue.h"

void pr_stdio( const char *, FILE * );

int 
main( void )
{
        FILE *fp;
        fputs( "enter any character
", stdout );
        if( getchar() == EOF )
                err_sys( "getchar error" );
        fputs( "one line to standard error
", stderr );

        pr_stdio( "stdin", stdin );
        pr_stdio( "stdout", stdout );
        pr_stdio( "stderr", stderr );

        if(( fp = fopen("/etc/mtab", "r")) == NULL)
                err_sys("fopen error");
        if(getc(fp) == EOF)
                err_sys("getc error");
        pr_stdio("/etc/mtab", fp);
        exit(0);
}

void
pr_stdio(const char *name, FILE *fp)
{
        printf("stream = %s, ", name);
        /*
        * The following is nonportable.
        */
        if(fp->_IO_file_flags & _IO_UNBUFFERED)
                printf("unbuffered");
        else if(fp->_IO_file_flags & _IO_LINE_BUF)
                printf("line buffered");
        else    /* if neither of above */
                printf("fully buffered");
        printf(", buffer size = %d
", fp->_IO_buf_end - fp->_IO_buf_base);
}

注意,在打印缓冲状态信息之前,先对每个流执行I/O操作,第一个I/O操作通常就造成为该流分配缓冲。结构成员_IO_file_flags、_IO_buf_base、_IO_buf_end和常量_IO_UNBUFFERED、_IO_LINE_BUFFERED是由Linux中的GNU标准I/O库定义的。应当了解,其他UNIX系统可能会有不同的标准I/O库实现。

如果运行程序清单5-3中的程序两次,一次使三个标准流与终端相连接,另一次使它们重定向到普通文件,则所得结果是:

[root@localhost apue]# ./prog5-3    stdin、stdout和stderr都连至终端
enter any character
                键入换行符
one line to standard error
stream = stdin, line buffered, buffer size = 4096
stream = stdout, line buffered, buffer size = 4096
stream = stderr, unbuffered, buffer size = 1
stream = /etc/mtab, fully buffered, buffer size = 4096
[root@localhost apue]# ./prog5-3 < /etc/termcap > std.out 2> std.err
                三个流都重定向,再次运行该程序
[root@localhost apue]# cat std.err
one line to standard error
[root@localhost apue]# cat std.out
enter any character
stream = stdin, fully buffered, buffer size = 4096
stream = stdout, fully buffered, buffer size = 4096
stream = stderr, unbuffered, buffer size = 1
stream = /etc/mtab, fully buffered, buffer size = 4096

从中可见,该系统的默认情况是:当标准输入、输出连至终端时,它们是行缓冲的。行缓冲的长度是4096字节。注意,这并没有将输入、输出的行长限制为4096字节,这只是缓冲区的长度。如果要将8192字节的行写到标准输出,则要进行两次write系统调用。当将这两个流重定向到普通文件时,它们就变成是全缓冲的,其缓冲区长度是该文件系统优先选用的I/O长度(从stat结构中得到的st_blksize值)。从中也可看到,标准出错如它所应该的那样是非缓冲的,而普通文件按系统默认是全缓冲的。

本篇博文内容摘自《UNIX环境高级编程》(第二版),仅作个人学习记录所用。关于本书可参考:http://www.apuebook.com/

原文地址:https://www.cnblogs.com/nufangrensheng/p/3506235.html