GHC Style guidelines for C code

Comments

These coding style guidelines are mainly intended for use in ghc/rts and ghc/includes.

NB These are just suggestions. They're not set in stone. Some of them are probably misguided. If you disagree with them, feel free to modify this document (and make your commit message reasonably informative) or mail someone (eg. The GHC mailing list)

References

If you haven't read them already, you might like to check the following. Where they conflict with our suggestions, they're probably right.

Portability issues

Debugging/robustness tricks

Anyone who has tried to debug a garbage collector or code generator will tell you: "If a program is going to crash, it should crash as soon, as noisily and as often as possible." There's nothing worse than trying to find a bug which only shows up when running GHC on itself and doesn't manifest itself until 10 seconds after the actual cause of the problem.

We put all our debugging code inside #ifdef DEBUG. The general policy is we don't ship code with debugging checks and assertions in it, but we do run with those checks in place when developing and testing. Anything inside #ifdef DEBUG should not slow down the code by more than a factor of 2.

We also have more expensive "sanity checking" code for hardcore debugging - this can slow down the code by a large factor, but is only enabled on demand by a command-line flag. General sanity checking in the RTS is currently enabled with the -DS RTS flag.

There are a number of RTS flags which control debugging output and sanity checking in various parts of the system when DEBUG is defined. For example, to get the scheduler to be verbose about what it is doing, you would say +RTS -Ds -RTS. See includes/RtsFlags.h and rts/RtsFlags.c for the full set of debugging flags. To check one of these flags in the code, write:

  IF_DEBUG(gc, fprintf(stderr, "..."));
would check the gc flag before generating the output (and the code is removed altogether if DEBUG is not defined).

All debugging output should go to stderr.

Particular guidelines for writing robust code:

Syntactic details

  • This code
    int* p, q;
    
    looks like it declares two pointers but, in fact, only p is a pointer. It's safer to write this:
    int* p;
    int* q;
    
    You could also write this:
    int *p, *q;
    
    but it is preferrable to split the declarations.

  • Try to use ANSI C's enum feature when defining lists of constants of the same type. Among other benefits, you'll notice that gdb uses the name instead of its (usually inscrutable) number when printing values with enum types and gdb will let you use the name in expressions you type.

    Examples:

        typedef enum { /* N.B. Used as indexes into arrays */
         NO_HEAP_PROFILING,		
         HEAP_BY_CC,		
         HEAP_BY_MOD,		
         HEAP_BY_GRP,		
         HEAP_BY_DESCR,		
         HEAP_BY_TYPE,		
         HEAP_BY_TIME		
        } ProfilingFlags;
    
    instead of
        # define NO_HEAP_PROFILING	0	/* N.B. Used as indexes into arrays */
        # define HEAP_BY_CC		1
        # define HEAP_BY_MOD	2
        # define HEAP_BY_GRP	3
        # define HEAP_BY_DESCR	4
        # define HEAP_BY_TYPE	5
        # define HEAP_BY_TIME	6
    
    and
        typedef enum {
         CCchar    = 'C',
         MODchar   = 'M',
         GRPchar   = 'G',
         DESCRchar = 'D',
         TYPEchar  = 'Y',
         TIMEchar  = 'T'
        } ProfilingTag;
    
    instead of
        # define CCchar    'C'
        # define MODchar   'M'
        # define GRPchar   'G'
        # define DESCRchar 'D'
        # define TYPEchar  'Y'
        # define TIMEchar  'T'
    

  • Please keep to 80 columns: the line has to be drawn somewhere, and by keeping it to 80 columns we can ensure that code looks OK on everyone's screen. Long lines are hard to read, and a sign that the code needs to be restructured anyway.

  • When commenting out large chunks of code, use #ifdef 0 ... #endif rather than /* ... */ because C doesn't have nested comments.

  • When declaring a typedef for a struct, give the struct a name as well, so that other headers can forward-reference the struct name and it becomes possible to have opaque pointers to the struct. Our convention is to name the struct the same as the typedef, but add a leading underscore. For example:
      typedef struct _Foo {
        ...
      } Foo;
    

  • Do not use ! instead of explicit comparison against NULL or '\0'; the latter is much clearer.

  • We don't care too much about your indentation style but, if you're modifying a function, please try to use the same style as the rest of the function (or file). If you're writing new code, a tab width of 4 is preferred.

    CVS issues