CS/CE 218 Lecture -*-Outline-*- connection: Let's step back and look at the really big picture of the C part of the course. We have studied C programming, but so far without much connection with the external world outside of C programs. So far we know how calculate within a program, use arrays, pointers, structs, etc. We also know a bit about how to interact with the external world: how to get command line arguments, how to read from standard input (using...), how to write to standard output (using ...), and how to set the program's exit status (using ...). We've started to see more interesting stuff in programs, FILE, fprintf, etc. What does it all do? How can we do all the stuff we learned about in shell programming, like write error messages to stderr? And why doesn't a message sent to printf appear on the terminal screen before "Bus error - core dumped"? * I/O Model advert: To be able to answer these questions, we need to understand the way C handles I/O and how it interfaces to the external world in general. We'll have to start by understanding why the way C deals with I/O and other externals is split into 2 parts... ** Portable vs. Unix-specific interactions with external world C runs on other operating systems besides Unix and Unix clones. These include DOS, the Macintosh, and old OS's like Multics, VM, MTS... Q: If you were defining C, how would you structure the language definition so users of non-Unix systems could write portable programs that did I/O? Stuff in chapter 7 is portable, since part of ANSI standard. Stuff in Chapter 8 is Unix specific... ** Standard I/O model The following isn't tied directly to the sections of K&R, but you should be able to read the details for yourself now... In the book what you may think of as a file is called a "stream" Why? Because input, for example, may come from a pipeline or a terminal instead of a file. A stream is a sequence of characters, you can consume them (input) or produce them (output). Just like pipelines. *** Buffering This is the reason your output doesn't show up when your program crashes. A buffer is an array of characters from a stream, it generally contains less than the whole stream. Q: Why would output to a file be buffered? Why buffer input? Efficiency is the main reason, fewer disk reads if each time read in a large chunk. Buffering input allows the user to edit it (remember the Unix erase and kill characters?) allows type-ahead too ----------------------- Output buffering user writes into buffer buffer-sized chunks only sent out when buffer is full use fflush to force output of smaller chunks Input buffering buffer-sized chunks only read when buffer is empty user reads from the buffer, removing characters from buffer ----------------------- Q: How would you write a debugging message? What happens if you get a core dump? Where should the message go? write debug_print(char *) send output to stderr ** FILE pointer (section 7.5) Q: Where is the buffer for a file stored? somewhere space has to be allocated for it Should the implementation rely on you to do that? no, so it does it itself in fopen the type of a struct with the buffer and other data about a stream is the type FILE declared in stdio.h *** fopen Q: How does the operating system connect a file name with a file? FILE *fp = fopen("filename", "r"); Q: What kinds of things does the OS check when you open a file? permissions, existence, ... fopen returns NULL if an error -------------- FILE *minsf; if ((minsf = fopen(mins_file_name, "r")) == NULL) { sys_err("cannot read %s", mins_file_name); } -------------- *** fclose An OS typically only has a limited number of files it will let a program have open, so you eventually have to close some int fclose(FILE *); this flushes the buffers too *** other f-functions: fprintf, fscanf, fflush, fgets, fputs versions of printf and scanf available for arbitrary files Q: How do you print "error message" on stderr? *** s-functions: sprintf, sscanf formatted output to and from strings *** v-functions: va_list arguments (skip) useful in routines that have variable argument lists Describe the error routines in print_error.c *** example, the pg program Q: Can you write the pg program? pg [file ...] prints 22 lines, waits for user input... What does the main program do? check arguments, use stdin if none open files, do printing Use print subroutine to print 22 lines from fp. use fgets should 22 be a parameter? check that it's flushed read something, exit on EOF, error, or "q" How to read something? Can we read from stdin? How to get to the terminal? (/dev/tty). divide class up into groups of 5, have some groups code main, some print, some ttyin ** file descriptors (section 8.1) How is standard I/O implemented? in Unix... In Unix streams all look like files. Unix is protective of how it represents files and their bits. Why? allows changes, but more important, there are lots of different kinds of files (e.g., the terminal, a disk, ...) So Unix doesn't let you have even a pointer, instead it gives you a small non-negative integer, the file descriptor We've already seen these in shell programming 0 = stdin (not the stdin in stdio.h, where stdin is a FILE *) 1 = stdout 2 = stderr somewhere in a FILE * is a file descriptor (and a buffer, etc.) The function fileno takes a FILE * and returns its file descriptor Different file descriptors may be used for the same file (/dev/tty).