Phyllis Nelson is currently finishing her PhD in solid-state and quantum electronics at UCLA. An important part of her research has been the design and construction of computer-controlled experiments. She also works part time for TRW, where she is presently characterizing infrared detectors made from high-termperature superconducting materials. She may be contacted at UCLA Department of Electrical Engineering, 7619 Boelter Hall, Los Angeles, CA 90024-1596.
C Programming In A UNIX Environment is a text intended to teach those with a solid programming background how to write UNIX-based C programs.
Both UNIX and C were written to provide tools for programmers. UNIX provides a plentiful set of elementary but adaptable tools designed to be linked together, and C is an operator-rich language with which to write new tools as they are needed.
This operating system and compiler are unusually free of restrictions, giving the programmer exceptional flexibility. The disadvantage is that actions which are considered errors in almost every high-level language are accepted by a C compiler. For example, C will allow you to write to arr[25] even though you declared the array arr to have only 20 elements. This operation is almost invariably the result of an error in generating the array index, and the normal consequence is that you unintentionally modify the value of another variable. Most compilers will reject such suspicious code, while C will not even give a warning.
Two independent tools are available for identifying questionable code. One is the assert() function included in the standard C libraries. In the above example, assert(i >= 0 && i < 20) checks that the array index i is within the intended limits before writing to memory. The more usual approach is to use lint, a sophisticated C syntax analysis tool, to screen the code. Thus, exhaustive error checking is available, but only if the programmer explicitly requests it.
C programmers have evolved a number of idioms and conventions, collectively called "good programming style". Although good habits are important in any programming environment, in C they defend against some especially insidious and troublesome bugs. The price of C's flexibility is the additional complexity of using lint as well as the compiler itself.
Introducing programmers to this freewheeling environment is a challenge. An unusually large number of commands and operators, together with a truly awesome assortment of nasty bugs, await the unwary. First-time computer users are often bewildered by this diversity, while those making the transition from more structured environments typically have several exasperating bug quests before they learn practical C self-defense techniques.
C Programming in a UNIX Environment is a useful addition to the literature because the authors stress the elements of good C programming style. They point out how the tools paradigm influences the programming process, and are meticulous in following a consistent, comprehensive approach to the inclusion of error traps.
This book gets right down to business. By the end of the first chapter, the authors have presented a multi-function program, discussed how to compile and run a single-file program and introduced lint. I like the way the authors point out that, in keeping with the UNIX philosophy, lint is separate from the C compiler because it does a different job. Kay and Kummerfeld are unusually scrupulous in presenting "lint-free" code. Even though I have written in C for a number of years, I picked up several useful new techniques from their examples.
The first half of the book is a brief introduction to C. The technique used to present new ideas, teaching by example, is particularly well-suited to experienced programmers. Each new concept is introduced in a code fragment, prefaced by a minimal description of the context. The code is then dissected in detail. Often I skim code fragments in texts because they are so thoroughly described in the accompanying prose. In this book, I felt challenged to see if I could not only understand the fragments before they were analyzed, but also anticipate the points being illustrated.
The next quarter of the book discusses C libraries. Even though I have seen most of the material before, I felt overwhelmed by the rapid pace of the presentation. I/O, file operations, storage allocation and string handling are all covered briefly but carefully in the first two thirds of the chapter.
The rest of the chapter is an introduction to the system interface functions. This last section is much too brief for the importance and complexity of the material, and is the one part of the book which I would not recommend for self-study. The authors clearly intend to give the reader a feeling for the breadth and power of the system calls. They suggest that, since some knowledge of UNIX is required, the section should be skimmed on a first reading. Unfortunately, the overview is so densely written that it is easy to confuse closely-related functions unless one reads very slowly. A few more pages of description and examples would help considerably to break up what frequently is little more than a list of function declarations.
The one redeeming feature of this discussion is its references to the UNIX Programmer's Manual. The whole chapter on C libraries is best viewed as a list of functions to look up in the manual. Reading the text and the manual together would give an excellent introduction to the available functions.
The final chapter is devoted to program development, and I thought it was the best part of the book. The authors take as their example constructing a simple mailing list system. They first choose a format for the data file, and then proceed to write some filters which can be pipelined with standard UNIX tools to select and sort groups of records, print mailing labels and print form letters. As the example unfolds, the original choices of file format and data representation are revisited and the consequences of the chosen form are explored.
The chapter presents a simple but unusually realistic example of the process by which applications programs are developed in the UNIX environment by combining new and existing tools. Although the mailing list system is rudimentary, it is representative of the early stages of a typical project. The real strength of this example is how well it illustrates the productivity of the C-UNIX relationship.
Several appendices give summaries of C syntax, operators and storage classes. The answers to the exercises are provided, which is especially valuable to those who use the book for self-study.
This book could be used as the text for a course in either academic or industrial settings. In addition, with the exception of the coverage of the system interface library functions, it would be a good choice for self-study by an experienced programmer. The authors have taken special care to ease the transition from Pascal to C by pointing out the differences in both philosophy and syntax. This transition is increasingly likely in the academic setting, where Pascal is frequently taught as the first programming language.
Two themes unify the exposition: the importance of disciplining oneself to follow good programming style and the benefits of integrating C and UNIX. It should, however, be supplemented with both an introductory UNIX text and the UNIX Programmer's Manual to take full advantage of the close relationship of C to its original environment. As with any programming text, the reader should also have access to a UNIX machine and a C compiler.
C Programming In A UNIX Environment
Judy Kay and Bob Kummerfeld
Addison-Wesley (1989)
softcover, 340 pages.