NOTE!!
This document is a growing document. It is a handy reference.
By all means bookmark it at home! But if you print it, you'll
likely end up killing another tree later when things are added
or changed. Style conventions change much like clothing styles --
just not as fast.
Below are some common style conventions in C. Follow them
as you would the rules of the road. (No, wait, follow them
better than you do the rules of the road. *grin*)
- place declarations at the top of each function
Even though some compilers will allow you to create constants/variables at
any point in the program, convention holds that it is much
easier to read a program when variables don't continually
pop up throughout the program. It also helps keep your
thoughts clear and organized if you try to place all of
your variables at the top of the function to begin with.
It's fine if you forget some, just put them in later (when
the compiler tells you to, most likely). But be sure to
place them with all of the others at the top of the function.
- use constants
Whenever you have some physical (acceleration due to gravity,
Avagadro's number), mathematical (pi), or economic (tax rates,
interest rates, etc.)
constant in a program, it is wise to make it a constant.
You will often also have symbols used in a program ('R' is
Thursday, for instance) that would do better as constants
(const char Thursday = 'R';
).
- good identifiers
An identifier is the word used to identify a variable, constant,
data type, or function. This identifier should start with a
letter (it can start with an underscore (_), but we
try to reserve that for standard library names). The identifier
can thereafter contain letters, underscores, or digits. Case
is significant! The length limit on identifiers is something you'd
not likely reach any day soon.
Make the identifiers you choose representative of the real-world
(or problem) meaning of the thing it identifies. Don't use names
such as t
when time
is more clear (and
time_of_departure
is even more clear, but a little
much to type). Don't use names such as bob
-- what
would this possibly mean, anyway?!
Often people have constants in all upper case, data types in
mixed case, and variables and function names in lower case.
Other people don't. It would be a good thing for you to pick
a capitalization style and stick with it. The all-caps constants
is really handy, for instance.
- blank lines
Blank lines within a program help to draw attention to logical
steps within the code. It is common to put a blank line before
each grouped segment of statements (similarly to where one puts
comments) -- often in front of the comment for that group.
Blank lines within a program's output help to focus the user's
attention on shifts in content: I was inputting data, now I'm
printing output.
- line wrap
Long lines work fine for the editor and compiler, but the printer
really abhors them. It will most commonly chop them off around
75-80 characters. Try to keep your lines at that length. Remember,
a single statement can wrap around several lines.
This rule applies to output lines, too. Don't let them wrap at the
user's screen boundary. Put in \n
's and/or
endl
's to break long output lines appropriately.
- indention
It is important to indent to clarify the flow of the program.
Whenever you open a curly brace ({), you should indent within
it by one level. When you close a curly brace (}), you should
unindent it (the close curly) by one level. What should a level
be? Commonly a level is between 3 and 5 spaces. One or two
spaces doesn't provide much of a clue (if the font is small) that
the indention has shifted. The common tab's 8 spaces is quite
deep (considering that you may have multiple indents stacked up
and we only have 75-80 characters per line). (This also implies
that you should avoid use of the tab for indention. I know it
is convenient, but it will really screw up your program's style.)
Another place to indent is when you wrap a line. The second line should
be indented at least to the first operator in the prior line. Often
other indentions make sense, too. Also try to break the original
line at a sensible point -- keep parenthesized expressions together
if at all possible.
- comments
Comments are there to clarify unclear code. Well written code will
have a feature known as self-documentation. This means that just
reading the code (without comments) should give you a pretty good
idea of what is going on. However, even self-documented code needs
a little push now and again. Traditional comments help to ensure
the clarity of your code.
Comments should be placed to the right of or before (preferred)
the line(s) they comment. Comments that come after what they comment
do less good. Comments to the left are cluttery and obscure.
The more confusing your code, the more you should lean to a clear
comment before the code. If the code is only slightly confusing,
a note to the right might be appropriate.
Comments should relate the code to the real-world process/problem.
They should NOT explain features of the C language.
If someone is reading code to learn to program, they can either
figure it out themselves or by a book or take a class. Most people
reading your code are already programmers and don't need to know
that double x, y;
declares two large floating point
variables. They'd be more interested to know that x
and y
represented the 2D coordinates of the upper
left corner of a rectangle.
Comments are most common in a few places: obscure/difficult code
(most likely this would be modulo uses, string processing, and/or
pointer math uses), branches (either one comment before the whole
branch or one on each case of the branch), loops (before is most
common, but sometimes programmers put one comment on each continuation
condition), functions (each function should have a comment before
it -- prototype and/or definition -- describing its behavior, its
return type, and its arguments; details on how it works should be
commented within the definition -- not in the header comment), and
logical groupings (as mentioned above, people often comment a
group of statements that together perform some task -- even sequential
ones).
- avoid the
int
type
The data type int
should only be used when connecting
to OS features. The type int
changes size with various
operating systems. Therefore, it should be avoided for application
bound data. Only use it when interfacing with the OS (for instance
the return type on main
). When designing your own
program's variables/constants, choose short
for small
integers or long
for large integers.
- use braces on all structures
Even though braces ({}) are optional on the flow control structures,
it is a good idea to always include them. It makes your structures
neater and easier to read. A half-braced structure simply looks
lame.
This practice will also save you hassels when you need to
add a statement to a branch or loop that wasn't previously braced.
A common mistake in this situation is to forget to add the braces
on the structure -- even though they are now needed as you've added
a second (or more) statement. If this extra statement is before an
else
, the compiler will catch it. In all other situations,
however, you'd have to notice it as a (fairly) subtle logic error.
Having had braces on all structures from the beginning would have
avoided this common mistake.
- branches should connect
Never place exit
calls, return
s, or other
such code inside a branch. Branches were meant to connect together
-- they entered at the top and should exit all together at the bottom
to continue on with whatever comes afterward. (The single exception
here is the use of break
in a switch
. This
is necessary as the switch
cannot work correctly without
them.)
- a loop is a circle with a (single) tail
Loops should not have multiple exit points (just as branches shouldn't).
A loop should continue to flow in a circle until the continuation
condition fails, at which point it will continue executing with the
next statement after the loop.
- functions should exit through a single point
A function has a single entry point: the call. It should likewise
have a single exit point: the return
. That implies
that each function should have a return
statement (even
functions with a void
return type) and only one
return
statement.
- avoid
break
, continue
, and goto
break
should only be used in a switch
structure.
No where else is it required. If you want a loop to end early, make it
an indefinite loop and add an extra condition. continue
can
similarly be avoided by proper use of structured programming.
goto
is simply there because earlier languages had it.
It can be used
to make code more efficient, but MUCH less readable.
#include
only as necessary
Only #include
a library's header if you are going to
use items from that library (functions, constants, etc.) in the
current file. Don't say you are using a library, for instance,
in a header if you don't use it there. If the implementation
uses items from a library, it should #include
that
library's header itself. #include
'ing many/all headers
shows that you don't really understand how or why the libraries'
features work. It can also slow down your compilation a great
deal. It might do you well to include a comment with each
#include
that lists exactly which features you are
using from that library. This will keep you better in mind
of why/how you are using libraries.