Section 5.12. Implementation Details

team bbl


5.12. Implementation Details

As we've mentioned, under the UNIX System, the standard I/O library ends up calling the I/O routines that we described in Chapter 3. Each standard I/O stream has an associated file descriptor, and we can obtain the descriptor for a stream by calling fileno.

Note that fileno is not part of the ISO C standard, but an extension supported by POSIX.1.

 #include <stdio.h> int fileno(FILE *fp); 

Returns: the file descriptor associated with the stream


We need this function if we want to call the dup or fcntl functions, for example.

To look at the implementation of the standard I/O library on your system, start with the header <stdio.h>. This will show how the FILE object is defined, the definitions of the per-stream flags, and any standard I/O routines, such as getc, that are defined as macros. Section 8.5 of Kernighan and Ritchie [1988] has a sample implementation that shows the flavor of many implementations on UNIX systems. Chapter 12 of Plauger [1992] provides the complete source code for an implementation of the standard I/O library. The implementation of the GNU standard I/O library is also publicly available.

Example

The program in Figure 5.11 prints the buffering for the three standard streams and for a stream that is associated with a regular file.

Note that we perform I/O on each stream before printing its buffering status, since the first I/O operation usually causes the buffers to be allocated for a stream. The structure members _IO_file_flags, _IO_buf_base, and _IO_buf_end and the constants _IO_UNBUFFERED and _IO_LINE_BUFFERED are defined by the GNU standard I/O library used on Linux. Be aware that other UNIX systems may have different implementations of the standard I/O library.

If we run the program in Figure 5.11 twice, once with the three standard streams connected to the terminal and once with the three standard streams redirected to files, we get the following result:

     $ ./a.out                       stdin, stdout, and stderr connected to terminal     enter any character                                     we type a newline     one line to standard error     stream = stdin, line buffered, buffer size = 1024     stream = stdout, line buffered, buffer size = 1024     stream = stderr, unbuffered, buffer size = 1     stream = /etc/motd, fully buffered, buffer size = 4096     $ ./a.out < /etc/termcap > std.out 2> std.err                                     run it again with all three streams redirected     $ cat std.err     one line to standard error     $ 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/motd, fully buffered, buffer size = 4096 

We can see that the default for this system is to have standard input and standard output line buffered when they're connected to a terminal. The line buffer is 1,024 bytes. Note that this doesn't restrict us to 1,024-byte input and output lines; that's just the size of the buffer. Writing a 2,048-byte line to standard output will require two write system calls. When we redirect these two streams to regular files, they become fully buffered, with buffer sizes equal to the preferred I/O sizethe st_blksize value from the stat structurefor the file system. We also see that the standard error is always unbuffered, as it should be, and that a regular file defaults to fully buffered.

Figure 5.11. Print buffering for various standard I/O streams
 #include "apue.h" void    pr_stdio(const char *, FILE *); int main(void) {     FILE    *fp;     fputs("enter any character\n", stdout);     if (getchar() == EOF)         err_sys("getchar error");     fputs("one line to standard error\n", stderr);     pr_stdio("stdin",  stdin);     pr_stdio("stdout", stdout);     pr_stdio("stderr", stderr);     if ((fp = fopen("/etc/motd", "r")) == NULL)         err_sys("fopen error");     if (getc(fp) == EOF)         err_sys("getc error");     pr_stdio("/etc/motd", 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\n", fp->_IO_buf_end - fp->_IO_buf_base); } 

    team bbl



    Advanced Programming in the UNIX Environment
    Advanced Programming in the UNIX Environment, Second Edition (Addison-Wesley Professional Computing Series)
    ISBN: 0321525949
    EAN: 2147483647
    Year: 2005
    Pages: 370

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net