Code is read much more often than written, and we must choose the best names to our variables/functions we can.
Sometimes we become obsessed by self explanatory names, and we add noisy to the reader without realizing it.
From the book:
for (theElementIndex = 0 ; theElementIndex < numberOfElements ; theElementIndex++) elementArray[theElementIndex] = theElementIndex;
This example may look insane and you may think you would never do this. But do you remember something like:
for (index = 0 ; index < numberOfElements ; index++) elements[index] = index;
index is just noisy. It’s scope is so small it doesn’t deserve that much information.
The book suggests just using
i as variable name.
Verbose isn’t the same as clear.
Programmers are often encouraged to use long variable names regardless of context. That is a mistake: clarity is often achieved through brevity.
Use active names for functions. Functions that return boolean values are an exception to this rule.
if (checkoctal(c)) ...
if (isoctal(c)) ...
The silliest it may look, it makes trouble. I was reading some code the other day and I had to read the implementation details to be sure the function doesn’t change any state. I wouldn’t need to do that if the author was aware of this hint.
1.2 Expressions and Statements
We are in 2012 and we still make indentation mistakes. Every time I see a
for loop like the following
I need to reread the lines around it about 3 times to be sure it means “no body here”:
for (n++ ; n < 100 ; field[n++] = '\0');
For God’s sake, add a body to it!
for (n++ ; n < 100 ; n++) field[n] = '\0';
Prefer using the natural form for expressions. Avoid Yoda conditions. If you speak the expression aloud and it sounds odd, change it.
Most of us can’t memorize operator precedence, so try to avoid trouble by adding parentheses to doubtful expressions and extracting subexpressions to variables.
1.3 Consistency and Idioms
The project’s consistency is more important than your own, because it makes life easier for those who follow.
Every programmer has it’s own style, and we create lots of idioms along our projects. Do not change any project coding style just because you don’t like it; preserve the coding style you have found.
1.4 Function Macros
I used to think I was really smart when I used to write inline functions using C preprocessor macros. I felt really good doing that. But the authors did me a favor writing:
Avoid function macros.
Function macros are not a good idea, since what they do is replace code. They can hide serious flaws:
#define isupper(c) ((c) >= 'A' && (c) <= 'Z')
It may look correct, but the problem is that inside
c is evaluated two times, and if
is used as
while (isupper(c = getchar())) ...
getchar is evaluated two times if
c >= 'A', and make you waste hours debugging it.
1.5 Magic Numbers
As a guideline, any number other than 0 or 1 is likely to be magic and should have a name of its own.
There is a trick in this section to calculate the number of elements of objects in C:
#define NELEMS(array) (sizeof(array) / sizeof(array))
And with this definition you have a dynamic size calculator in C!
Don’t belabor the obvious. This rule applies to all code like:
/* return SUCCESS */ return SUCCES; zerocount++; /* Increment zero entry count */
Sometimes we spend hours trying to improve comments, but what we may not realize is that we have bad code, and no matter how good the comment is, the code is not going to become better.
Don’t comment bad code. Rewrite it.
These were only some ideas behind the first chapter, and they are amazing!
The next chapters talk about complexity, how to grow arrays, how to implement hash tables, debugging, how they used to test code in the old times, performance hints and much more.
I loved the book. Go on and get your copy.
PS.: Rob Pike wrote in 1989 Notes on Programming in C, that is worth reading too.
Updates: 23/02/2012 - Fixed typos; Added book cover image