This appendix is not about indenting and placement of parentheses and curly braces, although that will be mentioned. This is about the general guidelines used in this book for organizing the code listings.
Although many of these issues have been introduced throughout th 13213o1418n e book, this appendix appears at the end so it can be assumed that every topic is fair game, and if you don't understand something you can look it up in the appropriate section.
All the decisions about coding style in this book have been deliberately made and considered, sometimes over a period of years. Of course, everyone has their reasons for organizing code the way they do, and I'm just trying to tell you how I arrived at mine and the constraints and environmental factors that brought me to those decisions.
In C, it has been traditional to name header files (containing declarations) with an extension of .h and implementation files (that cause storage to be allocated and code to be generated) with an extension of .c. C++ went through an evolution. It was first developed on Unix, where the operating system was aware of upper and lower case in file names. The original file names were simply capitalized versions of the C extensions: .H and .C. This of course didn't work for operating systems that didn't distinguish upper and lower case, like DOS. DOS C++ vendors used extensions of hxx and cxx for header files and implementation files, respectively, or hpp and cpp. Later, someone figured out that the only reason you needed a different extension for a file was so the compiler could determine whether to compile it as a C or C++ file. Because the compiler never compiled header files directly, only the implementation file extension needed to be changed. The custom, virtually across all systems, has now become to use cpp for implementation files and h for header files.
A very important issue with this book is that all code that you see in the book must be automatically extractable and compilable, so it can be verified to be correct (with at least one compiler). To facilitate this, all code listings that are meant to be compiled (as opposed to code fragments, of which there are few) have comment tags at the beginning and end. These tags are used by the code-extraction tool ExtractCode.cpp in chapter 23 to pull each code listing out of the plain-ASCII text version of this book (which you can find on the Web site https://www.BruceEckel.com).
The end-listing tag simply tells ExtractCode.cpp that it's the end of the listing, but the begin-listing tag is followed by information about what subdirectory the file belongs in (generally organized by chapters, so a file that belongs in Chapter 8 would have a tag of C08), followed by a colon and the name of the listing file.
Because ExtractCode.cpp also creates a makefile for each subdirectory, information about how a program is made and the command-line used to test it is also incorporated into the listings. If a program is stand alone (it doesn't need to be linked with anything else) it has no extra information. This is also true for header files. However, if it doesn't contain a main( ) and is meant to be linked with something else, then it has an after the file name. If this listing is meant to be the main program but needs to be linked with other components, there's a separate line that begins with // and continues with all the files that need to be linked (without extensions, since those can vary from platform to platform).
Here's an example of a stand-alone program:
Here's a more complicated example that involves two header files, two implementation files and a main program that requires a link line:
Here's the makefile that ExtractCode.cpp generated for this appendix:
If a file should be extracted but the begin- and end-tags should not be included in the extracted file (for example, if it's a file of test data) then the begin-tag is immediately followed by a '!', like this:
You may notice the formatting style in this book is different from many traditional C styles. Of course, everyone feels their own style is the most rational. However, the style used here has a simple logic behind it, which will be presented here mixed in with ideas on why some of the other styles developed.
The formatting style is motivated by one thing: presentation, both in print and in live seminars. You may feel your needs are different because you don't make a lot of presentations, but working code is read much more than it is written, so it should be easy for the reader to perceive. My two most important criteria are "scannability" (how easy it is for the reader to grasp the meaning of a single line) and the number of lines that can fit on a page. This latter may sound funny, but when you are giving a live presentation, it's very distracting to shuffle back and forth between slides, and a few wasted lines can cause this.
Everyone seems to agree that code inside braces should be indented. What people don't agree on, and the place where there's the most inconsistency within formatting styles is this: where does the opening brace go? This one question, I feel, is what causes such inconsistencies among coding styles (For an enumeration of coding styles, see C++ Programming Guidelines, by Tom Plum & Dan Saks, Plum Hall 1991). I'll try to convince you that many of today's coding styles come from pre-Standard C constraints (before function prototypes) and are thus inappropriate now.
First, my answer to the question: the opening brace should always go on the same line as the "precursor" (by which I mean "whatever the body is about: a class, function, object definition, if statement, etc."). This is a single, consistent rule I apply to all the code I write, and it makes formatting much simpler. It makes the "scannability" easier - when you look at this line:
void func(int a);
you know, by the semicolon at the end of the line, that this is a declaration and it goes no further, but when you see the line:
void func(int a)
Here, it would be quite ungainly to put the opening brace on the same line, so no one did it. However, they did make various decisions about whether the braces should be indented with the body of the code, or whether they should be at the level of the "precursor." Thus we got many different formatting styles.
There are other arguments for placing the brace on the line immediately following the declaration (of a class, struct, function, etc.). The following came from a reader, and are presented here so you know what the issues are:
Experienced 'vi' (vim) users know that typing the ']' key twice will take the user to the next occurance of '
The above [asserts the reader] has poor scannability. However,
if (cond1
&& cond2
&& cond3
breaks up the 'if' from the body, resulting in better readability.
Finally, it's much easier to visually align braces when they are aligned in the same column. They visually "stick out" much better. [ End of reader comment ]
The issue of where to put the opening curly brace is probably the most discordant issue. I've learned to scan both forms, and in the end it comes down to what you've grown comfortable with. However, I note that the official Java coding standard (found on Sun's Java Web site) is effectively the same as the one I present here - since more folks are programming in both languages, the consistency between coding styles may be helpful.
The approach I use removes all the exceptions and special cases, and logically produces a single style of indentation, as well. Even within a function body, the consistency holds, as in:
for(int i = 0; i < 100; i++)
The style is very easy to teach and remember - you use a single, consistent rule for all your formatting, not one for classes, one for functions and possibly others for for loops, if statements, etc. The consistency alone, I feel, makes it worthy of consideration. Above all, C++ is a new language and (although we must make many concessions to C) we shouldn't be carrying too many artifacts with us that cause problems in the future. Small problems multiplied by many lines of code become big problems. (For a thorough examination of the subject, albeit in C, see David Straker: C Style: Standards and Guidelines, Prentice-Hall 1992).
The other constraint I must work under is the line width, since the book has a limitation of 50 characters. What happens when something is too long to fit on one line? Well, again I strive to have a consistent policy for the way lines are broken up, so they can be easily viewed. As long as something is all part of a single definition, it should .
Headers are included from "the most specific to the most general." That is, any header files in the local directory are included first, then any of my own "tool" headers such as require.h or purge.h, then any third-party library headers, then the standard C++ library headers, and finally the C library headers.
The justification for this comes from John Lakos in Large-Scale C++ Software Design (Addison-Wesley, 1996):
Latent usage errors can be avoided by ensuring that the .h file of a component parses by itself -- without externally-provided declarations or definitions... Including the .h file as the very first line of the .c file ensures that no critical piece of information intrinsic to the physical interface of the component is missing from the .h file (or, if there is, that you will find out about it as soon as you try to compile the .c file).
If the order of header inclusion goes "from most specific to most general," then it's more likely that if your header doesn't parse by itself, you'll find out about it sooner and prevent annoyances down the road.
Include guards are always used in headers files [more detail here].
[More detail will be given here]. In header files, any "pollution" of the namespace in which the header is included must be scrupulously avoided, so no using declarations of any kind are allowed outside of function definitions.
In cpp files, any global using definitions will only affect that file, and so they are generally used for ease of reading and writing code, especially in small programs.
The require( ) and assure( ) functions in require.h are used consistently throughout most of the book, so that they may properly report problems. [more detail here]
|