There should be only one statement per line unless the statements are very closely related.
case FOO: oogle (zork); boogle (zork); break;
case BAR: oogle (bork); boogle (zork); break;
case BAZ: oogle (gork); boogle (bork); break;
for
or
while
loop should be alone on a line and commented
so that it is clear that the null body is intentional
and not missing code.
while (*dest++ = *src++)
; /* VOID */
Do not default the test for non-zero, i.e.
if (f() != FAIL)
if (f())
FAIL
may have the value 0 which C considers to be false.
An explicit test will help you out later when somebody decides that a
failure return should be -1 instead of 0.
Explicit comparison should be used even if the comparison value will
never change; e.g.,
``if (!(bufsize % sizeof(int)))
''
should be written instead as
``if ((bufsize % sizeof(int)) == 0)
''
to reflect the numeric (not boolean) nature of the test.
A frequent trouble spot is using
strcmp
to test for string equality, where the result should never
ever be defaulted.
The preferred approach is to define a macro STREQ.
#define STREQ(a, b) (strcmp((a), (b)) == 0)
The non-zero test is often defaulted for predicates and other functions or expressions which meet the following restrictions:
It is common practice to declare a boolean type
``bool
''
in a global include file.
The special names improve readability immensely.
typedef int bool;
#define FALSE 0
#define TRUE 1
typedef enum { NO=0, YES } bool;
Even with these declarations, do not check a boolean value for equality with 1 (TRUE, YES, etc.); instead test for inequality with 0 (FALSE, NO, etc.). Most functions are guaranteed to return 0 if false, but only non-zero if true. Thus,
if (func() == TRUE) { ...
if (func() != FALSE) { ...
if (isvalid()) { ...
There is a time and a place for embedded assignment statements. In some constructs there is no better way to accomplish the results without making the code bulkier and less readable.
while ((c = getchar()) != EOF) {
process the character
}
++
and
--
operators count as assignment statements.
So, for many purposes, do functions with side effects.
Using embedded assignment statements to improve run-time performance
is also possible.
However, one should consider the tradeoff between increased speed and
decreased maintainability that results when embedded assignments are
used in artificial places.
For example,
a = b + c;
d = a + r;
d = (a = b + c) + r;
Goto statements should be used sparingly, as in any well-structured
code.
The main place where they can be usefully employed is to break out
of several levels of
switch
,
for
,
and
while
nesting,
although the need to do such a thing may indicate
that the inner constructs should be broken out into
a separate function, with a success/failure return code.
for (...) {
while (...) {
...
if (disaster)
goto error;
}
}
...
error:
clean up the mess
goto
is necessary the accompanying label should be alone
on a line and tabbed one stop to the left of the
code that follows.
The goto should be commented (possibly in the block header)
as to its utility and purpose.
Continue
should be used sparingly and near the top of the loop.
Break
is less troublesome.