Home UC3M
Home IT
Home / Teaching / Telecommunication Engineering / Laboratorio de Arquitectura de Ordenadores / C-Coding conventions
anteriorsiguiente


 C-Coding conventions

The content of this document has been extracted from Tcl/Tk Engineering Manual", by J. K. Ousterhout, May 1996.

This is a simplified and slightly modified summary of the above document which is in turn is a manual for people who are developing C code for an application called Tcl/Tk. It describes a set of conventions for writing code. Ousterhout mentions three reasons for the conventions:

  • ensure that certain important things get done: for example, every procedure must have documentation
  • guarantee all the code has a uniform style. This makes it easier to use, read and maintain.
  • help to avoid some common mistakes by prohibiting certain constructs in C such as ++ and -- operators in the middle of expressions (for example in a condition of an if-then-else).

Please, write your code so that it conforms to these conventions from the very start.

General Conventions

  • Each source code file should contain a related set of procedures. Before writing code you should think carefully about what functions are to be provided and divide them into files in a logical way. C files should not have more than 2000 lines.
  • Each procedure should be preceded by a header that gives overall documentation followed by the declaration and the body. The header is written as a comment and should include the name and a brief explanation of the procedure, explanation about the result that it returns (if any) and finally, side effects that might occur.
  • Procedure declaration should include as the first line the type of the procedure's result. All procedures must be typed. Use void if there is no result. The second line gives the name and its argument list. If they are too many, they may spill into several lines.
  • Order the parameters in a declaration by relevance. Most important parameters go first.

Naming Conventions

The ideal variable name is one that instantly conveys as much information as possible about the purpose of the variable it refers to. Some things to consider are:

  • Are you consistent? Use the same name for the same thing everywhere.
  • Could this name be confused with some other name?
  • Is the name so generic that it doesn't convey any information?

It follows a set of specific rules governing syntax of names.

  • Variable names must start with lower-case letter. Procedure and defined type names always start with an upper-case letter.
  • In multi-word names, the first letter of each trailing word is capitalized.
       int counter;
       extern char *FindElement();
       typedef int Boolean;
    	
  • Any name that refers to a pointer ends in Ptr. If a name refers to a pointer to a pointer, then it ends in PtrPtr, and so on. The rule does not apply to strings, despite the fact that are represented as pointers to char, the suffix Ptr is not needed.
       TkWindow *winPtr;
       char *name;
       char **namePtr;
    	
  • Constants defined with #define should have names with all capital letters. Macros that code simple procedures should have only the first letter capitalized.
      #define NULL 0
      #define BUFFER_SIZE 1024
      #define Min(a,b) (((a) < (b)) ? (a) : (b))
    	

Low-level coding conventions

  • Each level of indentation should be four spaces. Set your favourite editor to follow this basic rule.
  • Code comments occupy full lines. Comments that document code should occupy full lines rather than being tacked onto the ends of lines containing code. The comment should be indented to the same level as the surrounding code.
  • When documenting the arguments for procedures and the members of structures, place the comments side by side on the same lines as the declarations.
    typedef struct VarTrace {
        Tcl_VarTraceProc *traceProc;/* Procedure to call when operations given
                                     * by flags are performed on variable. */
        ClientData clientData;      /* Argument to pass to proc. */
        int flags;                  /* What events the trace procedure is
                                     * interested in:  OR-ed combination of
                                     * TCL_TRACE_READS, TCL_TRACE_WRITES, and
                                     * TCL_TRACE_UNSETS. */
        struct VarTrace *nextPtr;   /* Next in list of traces associated with
                                     * a particular variable. */
    } VarTrace;
    	
  • Curly braces: { goes at the end of a line. They should not appear on lines by themselves. Instead, they should be plaed at the end of the preceding line. Closed curly braces always appear as the first non-blank character on a line. Always use curly braces around a compound statement even if there is only one statement in the block:
        /* INCORRECT */
        if (filePtr->numLines == 0) return -1;
    
        /* CORRECT */
        if (filePtr->numLines == 0) {
            return -1;
        }
    	

    There is one exception, when cascading else statements you may use a form like the following

        if (strcmp(argv[1], "delete") == 0) {
            ...
        } else if (strcmp(argv[1], "get") == 0) {
            ...
        } else if (strcmp(argv[1], "set") == 0) {
            ...
        } else {
            ...
        }
    	
  • Stick to lines with no more than 80 characters. If a line is longer than 80 characters, break its content into a continuation line. Continuation lines are indented 4 more spaces than the line before, to avoid confusion. Pick clean places to break your lines.
  • Switch statements have two levels of indentation, one for the switch keyword and one for each case statement:
        switch (src) {
              case `n':
                     dst = `\n';
                     break;
    
              case `t':
                     dst = `\t';
                     break;
    
              ...
        }
    	
  • Avoid macros except for simple things.
  • Always parenthesize expressions. They are easier to read.
        /* INCORRECT */
        if (x > 22 && y <= 47) ...
    
        /* CORRECT */
        if ((x > 22) && (y <= 47)) ...
    	

Documenting code

  • Document things with wide impact. The most important things to document are those that affect many different pieces of a program.
  • Don't just repeat what's in the code:
        /*
         * Increment i.
         */
        i += 1;
    	

    Documentation should provide higher-level information about the overall function of the code, helping readers to understand what a complex collection of statements really means. For example, the comment

        /*
         * Probe into the hash table to see if the symbol exists.
         */
    	

    is likely to be much more helpful than

        *
        * Mask off all but the lower 8 bits of x, then index into table
        * t, then traverse the list looking for a character string
        * identical to s.
        */
    	
  • Document each thing in exactly one place. If something is documented in several places, it will be hard to keep the documentation up to date as the system changes. Instead, try to document each major design decision in exactly one place, as near as possible to the code that implements the design decision.
  • Document as you go. It is extremely important to write the documentation as you write the code. It's very tempting to put off the documentation until the end; after all, the code will change, so why waste time writing documentation now when you'll have to change it later? The problem is that the end never comes ­ there is always more code to write.
  • Document tricky situations. If code is non-obvious, meaning that its structure and correctness depend on information that won't be obvious to someone reading it for the first time, be sure to document the non-obvious information.
Última Actualización 18/02/2004

Location | Personnel | Teaching | Research | News | Intranet
inicio | mapa del web | contacta