Standard indentation?
Doug Gwyn
gwyn at smoke.BRL.MIL
Sun Dec 11 14:27:46 AEST 1988
First, let's note that style issues are partly a matter of subjective
preference and partly objectively related to readability/maintainability.
In article <846 at starfish.Convergent.COM> jerry at starfish.Convergent.COM (Gerald Hawkins) writes:
>First, there is actually little disagreement on the basic idea of
>indenting code within a loop. How many spaces to indent seems to be
>purely a function of the width of your terminal or printer and the depth
>of nested loops. Whether or not all indents should be the same amount is
>never mentioned. I use TAB = 2 spaces for complex stuff and 4 spaces for
>simple stuff.
I have a wonderful utility I developed at Geotronics called "retab"
that remaps tabs in a single pass. It makes it possible to deal with
code written according to tab conventions other than the local standard.
The EMACS "filter-region" or sam "|" operations make it possible to
apply this locally as needed.
>The next major thing is where to put your '{' and '}'s.
The way I look at it is, the {} are part of a compound statement, not
part of the control syntax. (This is in fact technically accurate.)
> do
> {
> ...
> ...
> } while (x != EOF);
Therefore, I use
do
whatever
while ( condition );
The style you show assumes there will be {} in the controlled statement.
>Is it ever ok to use the form:
> if (a = b * 2 + 39) /* intentional assignment within condition */
In code I originate (rather than patches I apply, where I try to follow
the pre-existing style), I ALWAYS distinguish between Boolean and integer
expressions and variables. Therefore, I would agree that the above is
poor style, but have no problem with using
if ( initialized = root_ptr != NULL )
I even typedef int bool so I can declare "initialized" as properly
Boolean. This slight language extension seems to me so essential for
robust coding that I have it in my standard header <std.h> (along
with #define true 1 and #define false 0). I don't use C's implicit
comparison-against-zero feature other than in the form
if ( boolean )
if ( !boolean )
>If I have a code fragment which is used in only one place in one program,
>but it is very independent code (doesn't depend heavily on surrounding
>code), should I put that code into a function?
If it performs a cleanly isolated, well-defined function, then it would
be best to code it as a genuine function (unless it is in a tight loop).
Otherwise, leave it in-line but set it off with block comments:
/*
* Now walk through the tree,
* converting all unmarked nodes to
* undefined name references.
*/
(Actually I use a different style for block comments, but the above
is commonly encountered.)
Don't forget that you can declare an inner block with {} and thereby
restrict the scope of locally-introduced variables. This can be
carried to an extreme, but it is often handy. (For instance, in the
code after the above block comment, one may want a temporary register
node pointer variable.)
>When do you make the decision to use #define statements?
#define "magic numbers", fixed limits, and other constant parameters.
By using symbolic names, it is easy to globally change the values later.
#define function-like or Boolean macros when an actual function would
be obvious overkill:
#define slave_busy (sfname != NULL && sfp == NULL)
#define FreeName(name) (name==0 ? (void)0 : (free(name),(void)(name=0)))
Try to avoid #ifdef system_type kind of code as much as possible.
It can really cut down on readability and correctness. Often the
best way to cope with system dependencies is to isolate them in
separate functions provided in separate source files, with the same
interface on all systems but necessarily a different implementation
for each different kind of system. Then one uses whichever system
interface module is appropriate at "make time", and doesn't have a
bunch of conditionalized code cluttering up the rest of the sources.
>How much hard-coding is too much?
Almost any is too much. It is proper to use explicit constants when it
is clear what they mean and that they can never need to be changed. For
example, assigning 0 or 1 to initialize a counter is proper. Assuming
that 03 is always the right character code for a keyboard interrupt
character (i.e. ASCII ctrl-C) is not proper.
>When do you decide to create a library (ie, anytime a function is shared
>between two programs? Only when you are certain it is rock-solid? Only
>if it is used by many programs and will probably be used by many more?
There are two main kinds of library. First is a library of generally-
useful programming support functions (essentially a standard C library
extension). Second is a product-specific library, normally used only
for large programming projects. For the first kind of library, you
should put some work into defining the function interface to be as
generally useful as possible, and provide a header for each package
of related functions you put in the library. Also supply manual pages.
For example, we have a directory /vld/include full of package headers
and a corresponding library /vld/lib/libVMB.a with all sorts of useful
functions, for example various random deviate generators, complex
arithmetic support, spline-smoothing of data, etc.
>How do you decide how portable you want things to be?
If it is not a LOT of extra work to make things maximally portable,
it should be done from the outset, unless you KNOW you're going to
throw the code away almost immediately (e.g. it's just an experiment
that cannot be patched up to make anything generally useful). You
will be glad you did when you need your programs on another system
unlike the one you developed them on.
More information about the Comp.lang.c
mailing list