Path: utzoo!attcan!uunet!seismo!sundc!pitstop!sun!decwrl!purdue!mailrus!uflorida!haven!adm!smoke!gwyn From: gwyn@smoke.BRL.MIL (Doug Gwyn ) Newsgroups: comp.lang.c Subject: Re: Standard indentation? Message-ID: <9134@smoke.BRL.MIL> Date: 11 Dec 88 04:27:46 GMT References: <1988Dec8.173158.11839@utzoo.uucp> <846@starfish.Convergent.COM> Reply-To: gwyn@brl.arpa (Doug Gwyn (VLD/VMB) ) Organization: Ballistic Research Lab (BRL), APG, MD. Lines: 122 First, let's note that style issues are partly a matter of subjective preference and partly objectively related to readability/maintainability. In article <846@starfish.Convergent.COM> jerry@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 (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.