Book Reports


Advanced C: Tips And Techniques

Reviewed By Randy Hohl


Randy Hohl is a consultant with Interactive Systems Corporation. He has worked as an industry programmer for six years and has bachelor's degrees in computer engineering and psychology. He can be reached at (708) 505-9100 or randy@ i88. isc. com.

Advanced C: Tips and Techniques is the third installment in a series of four books on C Programming in the Hayden Books C Library. The first two books present the fundamentals of C. Advanced C emphasises portability, compiler code-generation, and execution speed. The book is authored by the team of Paul and Gail Anderson. The authors discuss some of the more difficult components of C using a variety of clever programming techniques.

The book is organized into six chapters and five appendices. Chapter one serves as a C refresher, the remaining chapters each cover a set of related topics. Every chapter concludes with a number of programming exercises. Each appendix details the features of a particular C compiler.

Chapter one introduces some portable techniques for swapping variable contents, ASCII-to-integer and decimal-to-hex conversions, and bit-level operations. The techniques recur throughout the book and are presented as program examples employing an advanced usage of unsigned variables, unions, casts and macros. This chapter sets the theme for the authors' low-level approach to writing efficient and portable C; some of the examples are simply assembly-language tricks converted to C.

Chapter two provides a comprehensive explanation of the C runtime environment. The compiler's distribution of program statements and variables into the text area, data area, the stack, and the heap is examined. This chapter answers questions like: "Where does a literal string live?" and "Is it faster to initialize static or automatic variables?" Examples are provided which demonstrate the compiler-mapping of program variables by printing the hex address of variables at runtime. I bought the book for this chapter and was thoroughly pleased. A complete source-code solution to the fragmentation of heap memory resulting from numerous runtime allocations is developed in chapter six.

You may not find a need for arrays of two or three dimensions very often, but if you do, chapter three, the longest in the book, is probably the most complete treatment of the subject available. Portions of this chapter read like formula derivations and proofs in a math text. This method is used to derive equivalent pointer expressions for multi-dimensional array references. The derivations are used to demonstrate the storage map equations used by a C compiler to evaluate array references. Other compiler formulae are also presented. I found this chapter to be rather complicated, but still valuable.

The authors show two methods to increase the speed of array referencing. Method one uses compact pointer expressions, such as *ptr++, rather than sequential pointer offsets, such as array[offset]; offset++. The argument here is that a compact pointer expression maps directly to a single assembler instruction. Method two uses pointer array declarations rather than multi_dimensional arrays. The methods are incorporated into a suite of ten benchmark programs which the authors have timed on 286, 386 and 68020 machines. The results show an average performance improvement of 27 percent using the optimized methods across the three architectures.

Ever been faced with a C declaration like, char *(*(*buf[20]) ())[10]? Complex declarations are succinctly deciphered in chapter four. The authors use a presentation mode developed in the preceding chapter, namely the repeated application of a rule, in this case the "Right-Left" rule. The Right-Left rule is simple and works nicely for both creating and reading complex declarations. This chapter also explains how to use varargs.h to create portable routines that accept a variable number of arguments.

Debugging techniques in C is the topic of chapter five. The authors develop six categories of custom debugging tools. Each category is predicated on surrounding utilities, including the C preprocessor, the assert() library routine, and the UNIX signal() system call. Some of the tools have the advantage of providing a variable degree of error-checking without the need to re-compile the original source, a big advantage in large systems. Where significant compile- or run-time overhead is required to implement a custom technique, the authors are quite frank about the tradeoffs involved. The value of some of these techniques took a while to sink in.

The appendices of the book are a well-written description of the AT&T C compiler and four different compilers targeted for Intel processors. All the options and all the memory models provided by each compiler are described. Chapter two's discussion of the C runtime environment is prerequisite knowledge for understanding the memory models. New constructs from the proposed ANSI C Standard are discussed for compilers which are supportive.

The book includes an order form for a set of two floppies, one containing the C source code for all the program examples, the other containing solutions to all the exercises. The price is $39.95. I examined the contents of both disks and was impressed. The examples disk contains over 150 .c files; each file contains a stand-alone C program drawn from the book. For book examples which are only code fragments, the fragment is expanded into a complete program. Nearly all examples make judicious use of printf statements to illustrate the subject matter. The solutions disk contains over 70 .c files, each an individual program. The solutions are complete and contain ample explanatory notes as C comments. Two of the chapter three solutions are timed on the 286.

Conclusions

I have mainly bravos for this book. Each topic is covered from both the compile-time and runtime perspectives. The authors incorporate portability and efficiency throughout, using the proper features of C. The presentation is well-paced and properly organized. All major points are illustrated with appopriate-length program examples. Some program examples are reused and enhanced in the light of the current topic. Advanced usage of some features of C, such as macro definitions with arguments, typedef variable types and compact conditional operator expressions, are shown implicitly in the program examples. Proven techniques, such as the benefit of compact pointer expressions, are used in subsequent programs. The use of customized standard header files is especially creative.

Each chapter can be digested as a single entity, allowing the reader an arbitrary perusal. The content of the exercise questions follows logically from each chapter's points; for instance, some of the chapter three exercises ask you to extend program examples to arrays of four dimensions.

The book's preface lists the eight combinations of five machines and seven C compilers in which all program examples were compiled and executed. The execution results of program examples in specific combinations is a regular part of the narrative. I was able to successfully compile select program examples and exercise solutions on an Amdahl 580 under UTS and an AT&T PC 6300 under MS-DOS.

Chapter two's discussion of the runtime environment is valuable for experienced programmers who are learning C; it may aid in preventing dangling pointer bugs. The remainder of the book is primarily useful for experienced C programmers, particularly those who are beyond "make it work" and are into the "make it clean" and "make it fast" stages. A working knowledge of the routines in a standard C library and their interfaces is also required. Proficiency in binary arithmetic is needed to work through the bit-level operations. I would also recommend a familiarity with UNIX shell commands and the UNIX System V system call, signal(). (The authors neglect to identify the signal() in the book as the System V, rather than Berkeley, version). I would have preferred some header file examples from an operating system library other than UNIX. Despite this bent toward the UNIX/XENIX family, the tips and techniques presented in the book are beneficial across operating systems.

Advanced C: Tips and Techniques
Paul and Gail Anderson
Howard W. Sams & Co. 1988
$24.95, 446 pages.