C Coding Conventions

Written by Udit Sajjanhar and Niloy Ganguly for Compiler Construction Lab. Comments welcome. You may redistribute or make copies of this document if you wish. You may also modify it. Some help has been taken from here.

Table of Contents

Introduction
Indentation
Line Breaking
Whitespace
Comments
Brace Placement
Naming
Function Declarations

Introduction

This document attempts to introduce common conventions. Coding Conventions are imporant becasue a code written in a ligitimate manner is always easy to maintain and debug. This document isn't intended to be an exacting standard that requires everything to be done in a certain way, but to lay down guidelines as to how things would ideally be done.Overall, its meant to promote consistency, both in a single programmers's code and between different programmers.

Examples have been given to try to clarify the meaning of the authors. Examples of code conforming to these conventions are shown as below.

Example of code encouraged by these guidelines

/**
* returns true when vec is at its end
* @param vec ....descreption about variable 'vec'....
* @returns ....descreption about what the function returns...
*/
int VecEof(const struct vec *v) {
  return (v->pos == v->len);
}

Examples of code not conforming to these conventions are shown as below.

Example of code discouraged by these guidelines: the bracing is placed on the next line and indentation required is 2 spaces per level

/* returns true when vec is at its end */
int vec_eof(const struct vec *v)
{
    return (v->pos == v->len);
}

Indentation

Whitespace used for formatting code should NEVER CONTAIN TABS, as they are subject to variation in interpretation. There is also no reason to use them, as the tab key in good editors can be reconfigured to insert a number of spaces instead of inserting a tab.

Indentation should be 2 spaces for each brace level of code. 2 was chosen because it was felt to be approximately the correct amount of indentation per level, and 2 is an even number, allowing half-indents for line breaking if desired.

Example of encouraged indentation

struct vec *VecInit(unsigned long int initsize) {
  struct vec *v = malloc(sizeof(*v));

  if (v && (v->vector = malloc(initsize))) {
    v->size = initsize;
    v->pos = v->len = 0;
    v->err = 0;
  } else if (v) {
    free(v);
  }

    return v;
}

Line Breaking

Lines should be limited to 80 characters in width, so as to fit into standard terminal displays without wrapping. How you choose to break your lines and indent the subsequent continued lines is left up to you. One method that you might like to use is to attempt to break lines before operators (particularly the logical boolean operators if the statement contains them) and half-indent the subsequent line by an additional two spaces. Whichever way you choose, please try to be consistent.

Example of discouraged (no) linebreaking: note that the text wraps on 80 character displays as shown below

    /*Set up the map file name*/
    snprintf(stats->tbuf, FILEBUF, "%s.%s.%s", stats->vocab[stats->iCurrVoc], INDSUF, MAPSUF);

Example of encouraged linebreaking

    /* Set up the map file name */
    snprintf(stats->tbuf, FILEBUF, "%s.%s.%s", stats->vocab[stats->iCurrVoc],
             INDSUF, MAPSUF);

Whitespace

Whitespace should be used to form the statement into as close an approximation to english as possible. This means that whitespace should be used between:
1. binary operators and operands
2. conditionals and their conditions ('if' is not a function)
3. after commas used to seperate parameters.
This rule can be bent in the interests of shorter lines, as long as the ultimate aim of keeping a line readable is kept in mind.

Empty lines should be used to seperate logical sections (like paragraphs in english text). However overuse of empty lines is discouraged as it makes less code fit on a screen, hence making code more difficult to read.

Example of discouraged spacing: not enough space

  /* preliminary code ... */
  for(i=0,eof=0;!eof;i++) {
    /* do stuff */
  }

  /* ... subsequent code */

Example of encouraged spacing

  /* preliminary code ... */

  for(i = 0, eof = 0; !eof; i++) {
    /* do stuff */
  }

  /* ... subsequent code */

Comments

The decision on when and what to comment is left to the good sense of the programmer with the following exceptions:

1. Each file should have a leading comment stating the following things about a file: the name of the file, the programmer's name and the creation date.

Example of Leading comment in the staring of the file.

/**
* Filename: LLParser.c
* Programmer Name: Udit Sajjanhar
* Date of creation : 27/07/07
*/

2. Each function should be preceded by a comment block describing in a few lines what the function does. It should also have @param, if the functions takes some parameters and @returns, if the function returns some value.

Example of comment block before functions

/**
* returns true when vec is at its end
* @param vec ....descreption about variable 'vec'....
* @returns ....descreption about what the function returns...
*/
int VecEof(const struct vec *v) {
    return (v->pos == v->len);
}

Comments, except in the above two cases should be formatted with an opening /* and a closing */. Additional asterisks should not be used in multi-line comments. Multiline comments should have the starting word of each line aligned with the first word of the first line (which should be indented to the current level of the code). Opening and sequences (/*) should be on the opening line of text. Closing sequences (*/) should be on the closing line of text the left hand edge of the code. Please note that C++ comments (//) are not appropriate in C code, as all ANSI C compilers will complain about them (if your compiler doesn't, you're not using enough warnings).

Example of discouraged commenting: two many asterisks

/** Assigning null to the pointer variable **/
vec = null;

Example of discouraged commenting: use of C++ comment

// Assigning null to the pointer variable
vec = null;

Example of encouraged commenting

/* Assigning null to the pointer variable */
vec = null;

Example of encouraged multiline commenting

/* vec.h declares an interface to create and access bytevectors, which
   can be dynamically read from, written to and expanded.
   based very closely on the old vec.[ch] written by Hugh Williams */

Brace Placement

Opening braces should be on the same line as the conditional or declarative statement that the brace is a part of. Closing braces should be on a line by themselves. This style was adopted to try and keep code length to a minimum, while retaining reasonable readability. The authors realise that not everyone agrees with this position, but we don't care :o). Seriously, there is probably no objective reasoning to prefer this to a brace-on-next-line style, so we chose the one we're most comfortable with.

Another issue in brace placement is whether to brace single statements in a conditional. The authors recommend bracing all statements in conditionals, as it makes adding more statements to it later easier and less error-prone.

Example of discouraged brace placement: opening braces on seperate lines and unbraced single statement

struct vec *VecInit(unsigned long int initsize)
{
  struct vec *v = malloc(sizeof(*v));

  if (v && (v->vector = malloc(initsize)))
  {
    v->size = initsize;
    v->pos = v->len = 0;
    v->err = 0;
  }
  else if (v)
    free(v);

  return v;
}

Example of encouraged brace placement

struct vec *VecInit(unsigned long int initsize) {
  struct vec *v = malloc(sizeof(*v));

  if (v && (v->vector = malloc(initsize))) {
    v->size = initsize;
    v->pos = v->len = 0;
    v->err = 0;
  } else if (v) {
    free(v);
  }

  return v;
}

Naming

Naming conventions apply to functions, macros, variables, files and so on. This document will not attempt to discuss the semantics of naming schemes, merely their format. The authors suggest using all uppercase names when the language construct is a textual operation, and a mixture of uppercase and lowercase names otherwise. This means that typedefs and macros (including preprocessor constants) should be declared using uppercase letters, and everything else should contain mixture of uppercase and lowercase letters. Multiword names should have the first word in lowercase and the first character of the subsequent words in uppercase. This convention is merely one of many, but is intended to be consistent and specify the difference between preprocessor operations and proper language operations, while minimising the variation (and hence inconsistencies) between all other names.

Example of discouraged naming method: use of non-capitalised macro and only lower case for multiword variables

#define Min(a, b) (((a) > (b)) ? (b) : (a))
  int isize,
  inumstrings;
  char **ppszstrings;

Example of encouraged naming method

#define MIN(a, b) (((a) > (b)) ? (b) : (a))
  int size, numStrings;
  char **stringArray;

Function Declarations

Each function body should be preceded by an comment block, which has been described avove in the comments section.
Each function name should begin with a uppercase character. For multiword function names, the first character of every word should be an upper case character.
The opening paranthesis should be on the same line as the function name.

Example of discouraged function declaration method: return type on seperate line

void
Sort(char *A, int n, int size, int (*cmp)(char *l, char *r)) {
  /* some code */
}

Example of discouraged function declaration method: brace on seperate line and multi word convention not followed.

void Sortcharacters(char *A, int n, int size, int (*cmp)(char *l, char *r))
{
  /* some code */
}

Example of encouraged function declaration method

/**
* this code sorts blah... blah.. blah...
* @param A .... descreption....
* @param n .... descreption....
* ....
* ....
*/
void SortCharacters(char *A, int n, int size, int (*cmp)(char *l, char *r)) {
  /* some code */
}

Please adhere to these conventions, as these will carry some marks in every assignment.