The University of Queensland Homepage
School of ITEE ITEE Main Website

 Coding style for COMP3201

Overview

This document details the coding style for comp3201.  By following this coding style you can avoid some of the pitfalls common to programmers new to C.  It also allows other programmers to read your code and understand it quickly (e.g. tutors).  Code submitted for assessment in comp3201 must follow the coding style detailed in this document. Code that does not follow the coding style will be subject to severe deductions.

Language

Code is to be written in C.  In particular it is to be ISO C90, commonly refered to as ANSI C.  We are not using ISO C99.  Those who are using gcc will find this easy to adhere to. Simply specifying "-ansi -pedantic" as command line options to gcc will turn off the GNU extensions. 

Those who use MS Visual C++ will have a slightly harder time adhering to the standard.  The first step is to make sure that you disable the Microsoft specific language extensions.  This is done by editing the project settings, choosing the C/C++ tab, change the category to "Customize", and ticking the box that says "Disable language extensions".  This does not completely enforce ISO C90 but gets you most of the way.  The second thing to do is be really really careful when you write your code.  For example, one deviation of the MSVC++ compiler is that C++ style comments are allowed.  Do not use these.  It is recommended that you test compile your code in a unix lab before submission.

The reason we are using ISO C90 in particular is to acheive platform independence.

Platform independence

The coding in comp3201 is to be platform independent.  To facilitate this GL types must be used for variables passed into GL functions.  Platform independence is also the reason for using ISO C90.  Submitted code will be examined on more that one platform so check that you can compile and run on more than one platform before submitting your code.

Comments

Comments must be of the usual C style (i.e. /* comment */ ) as opposed to the C++ style ( // comment ).
A small comment that can be made on a single line is formatted as
int numOfChickens;	/* This doesn't really need a comment */

Really important single line comments should use the multiline format.

If a comment goes over multiple lines then it should be formatted as follows.
/*
<tab>Before a function is usually a really long comment
detailing the purpose of the function and information
about the arguments.
*/

Comments should be indented to the level that they are describing.  For example,

for( i = 0; i < arraySize; ++i )
{
    int j = 0;
    /*
        A really important comment
    */
}

Naming convention

Variables are to start with lower case letters.  Uppercase letters may appear in the variable name to facilitate easy reading.  Variable names should reflect the application domain and not some cryptic abbreviation relating to the implementation domain.  Exceptions to this are variables for looping, indexing of arrays, and the standard arguments argc and argv.  For example,
float anotherVariable;  /* correct */
float flt; /* incorrect */

{
/* correct use of really short named variable */
int i;
for( i = 0; i < 10; ++i )
{
/* do something */
}
}
Abstract data types (i.e. structs and unions ) are to start with upper case letters.  Further uppercase letters may appear in the ADT name to facilitate easy reading.  For example
typedef struct TasDevil TasDevil;
struct TasDevil
{
char* pName;
TasDevil children[];
};
Pointers are to be prefixed with "p"; file scope variables (i.e. those defined with the keyword static) are to be prefixed with a "m";  global variables are to be prefixed with a "g".  When this convention needs two prefixes, the "m" or the "g" comes first.  It is impossible to need both an "m" and a "g" (Just think about it :) ).
/* At global scope */
extern TasDevil* gpDisneyTaz;
extern int gMaxDevils;

/* At file scope */
static TasDevil* mpDisneyTaz;

/* At local scope; e.g. inside a function */
TasDevil* pDisneyTaz;

Only one variable is to be declared per line, e.g.,
int x;		/* correct usage */
int y;
int z;

int x,y,z; /* incorrect */

Pointers are to be declared with the * next to the type.  This is not the usual C convention but is the usual C++ convention. It should be noted that if you are declaring more than one variable per line then this would be a really bad idea, but the previous rule prevents more than one variable per line :).  For example,

int* x;    /* correct according to this coding convention */
int *x;    /* incorrect - but the usual c style */
int * x;   /* you just look confused if you do this */

As a general rule of thumb, macros are evil and should not be used. However in ISO C90 they are still necessary and are a better alternative than hard coding constants.  A macro name is always to be in upper case.  For example,
#define PI 3.1415926535897932384626433832795028841971693993751058209749445923078164

Indentation

Set your editor to produce tabs that are 4 character wide. 

It is preferable to use tabs and not to replace the tabs with 4 spaces but there are times when this is a bad idea.

Abstract Data Types

Abstract data types are to be declared with a typedef so that the ADT looks like a first class type.  For example
typedef struct TasDevil TasDevil;
struct TasDevil
{
char* pName;
TasDevil* children;
};
TasDevil taz;

Functions

Keep them short.  If it is more than a screenful then ask yourself why is it so long. 

Function names follow the same naming convention as variable names (think about why).  That is, they start with a lower case letter and can have upper case letters for clarity.  Do not go for short cryptic function names but make the name reflect its purpose.

If the function isn't referenced by another file then make it static, i.e. file scope.  This helps the compiler to optimise.  For example

static int fibonacci( int index )
{
/* calculate the n'th fibonacci number. */
}

Braces

Place the braces on separate lines and ensure that they align vertically.  For example,
static int sumOneToTen( void )
{
int sum = 0;
int i;

for( i = 0; i <= 10; ++i )
{
sum += i;
}

return i;
}
Not that this means that we are not following the One True Brace Style of Kernighan and Richie.  While that was important in days when people worked on 24 line displays it gets in the way of code readability.

Source file organisation

Source files are to be created so the the interface to the module is in a header file and the implementation of the interface is in  a separate file.  Header files are to have a ".h" extension and implementation files are to have a ".c" extension. 

Filenames must be all lower case.  This will prevent cross platform issues arising due to MS Windows being not case sensitive and *nix being case sensitive.  Note that some of the system include directories must be upper case, e.g., #include <GL/glut.h>

Functions which are only used internally in a module must not to have prototypes in the header.  The header must not define variables but only declare global variables, i.e., a header can only contain statements like
extern double elevationAngle;    /* correct in header */
not
double elevationAngle;    /* incorrect in header.  this should be in some implementation file */
Header files must have guards to stop multiple inclusion.  For example
/* fish.h */

#ifndef FISH_H /* start of guard */
#define FISH_H

extern double someGlobalVariable; /* think hard before you use global variables in a program */
void drawFish( void );

#endif /* FISH_H */ /* end of guard */
 
An implementation file should be layed out so as to minimize forward declarations.  This has the implication that the main function will be located at the bottom of some implementation file.

An example of the above rules is as follows
/* main.c */

#if defined(__APPLE__) || defined(MACOSX)
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif

#include "fish.h"


GLvoid display( GLvoid )
{
/* lots of code */
    /* lots more code */
}

int main( int argc, char* argv[] )
{
/* lots of code */

glDisplayFunc( display );

    /* lots more code */

return 0;
}


/* fish.h */

#ifndef FISH_H
#define FISH_H

extern double someGlobalVariable; /* think hard before you use global variables in a program */
void drawFish( void );

#endif /* FISH_H */



/* fish.c */

#include "fish.h"

double someGlobalVariable; /* implementation of the global variable */

void drawFishTail( void )
{
/* lots of code */
}


void drawFish( void )
{
/* lots of code */

drawFishTail();

    /* lots more code */
}

Equivalence testing

When testing for equivalence of a variable and a constant, place the constant on the left.  For example
if( 0 == pObject )
{
/* do something */
}

The reason for this is that the compiler will now pick up typos.  For example, if you meant to write
if( pObject == 0 )
{
/* do something */
}
but actually wrote
if( pObject = 0 )    /* note the assignment instead of equivalence */
{
/* do something */
}
then the compiler would not object as this is legitimate C code.  However if you wrote
if( 0 = pObject )
{
/* do something */
}
then a compiler time error occurs as it is not legitimate C code.

Loops and conditional statements

In general a loop or conditional statement should be laid out as follows:
if( 0 == pObject )    
{
/* do something */
}
However if the "do something" is particularly short then write the statement as
if( 0 == pObject ){ fprintf( stderr, "Bad pointer\n" ); }
Note the presence of the braces.  Although C does not need braces for single line loops or conditionals we do require them in this coding style.

If there is need for a short if/then/else then use the conditional operator ?:.  For example
str = ( 0 == loop ) ? "true" : "false";

Build Process

The code must compile on *nix with the supplied standard makefile <TODO:link to standard makefile>.  On MSVC++ you must create your own workspaces.