Rules and recommendations for writing C/C++ source code

Introduction

Robot Control Software Ltd. provides source code of most libraries. To ensure the same look and feel for every source file we strictly follow the rules collected here.

Above of these rules all abbreviations used in type, function and variable names are collected in an abbreviation dictionary. Using this dictionary ensures that all abbreviations are unique and used in the same meaning by everyone.

1. Include Files

All header files must be enclosed with the following conditional defines:

#ifndef _Doc_PrgRules_h
#define _Doc_PrgRules_h

// the contents of the header file.

#endif //_Doc_PrgRules_h

The defined name is: _<path name>_<file name>_<file extension>. Under all file systems the file names should have extension such as .txt, .h, .hpp, .c, .cpp. ".h" is the preferred extension for header files even for C++ headers.

This ensures, that the definitions are compiled once even if the header file included several times.

2. File Header

All files must have a header like this:

/******************************************
Container Library
Stack Template Class

Copyright: 1996-2001
	Robot Control Software Ltd.
	http://www.rcs.hu

Author:
	Peter Barczikay [PBA] bpeter@rcs.hu

Tab size:
	any (4)
*******************************************/

The header must contain the following information:

The header must not contain:

3. Naming Conventions

Use English! All comments, variable and function names must be written in English!

Never use extra characters in source code. (Anything above #127.) It is not portable! (They may be used in strings if the language of the interface requires.)

The variable, type, class, and function names must be self explanatory. The words used in the name are separated by capital letters or underline '_'. The underline '_' character is recommended for higher level separation (for example to separate the prefixes and the name itself). Abbreviations may be used, but all abbreviations used in source files must be listed in the Abbreviation Dictionary in alphabetical order. This ensures, that one abbreviation is not used for two different word.

All exported name must have a prefix 'r' to identify RCS Ltd. and make our function, type, variable and file names different from names used in other libraries.

Generally Pascal naming convention is used (first letter of words are upper case: rFileIsOpend), but sometimes to highlight that the name has local scope we use the C naming convention (all letters are lower case and words are separated with underscore: file_is_opened).

The following prefixes are used to describe variable names more precisely:

aArgument
cConstant
eenum value
gGlobal variable
iIterator
mteMplate variable
pPointer
rReference
sStatic variable
_protected or private class member

The following prefixes are used to describe what the given type identifier means:

_cClass
_dDefine (macro)
_eEnumeration
_iInline function
_mteMplate (class or function)
_sStructure
_tType definition (typedef)
_uUnion

You can use other pre- and postfixes, but list them in the abbreviation file (abrev.txt)

Here is a few examples:

Abbreviations:

	Src - SouRCe
	Str - STRing

Source code:

class rStr_c{
protected:
	char *_pData;
	int _Size;
public:
	rStr_c(char *apSrc);
	rErr_t Insert(rStr &arStr);
	int Size() {return _Size;};
	void Size(int aSize) {_Size = aSize};
}; //class rStr_c

template <rData_m> class rStack {};

4. File Names and Directory Structure.

File names follows the same rules as program identifier names (see the previous section). The words of the file names are separated with upper case letters, but the file names must be unique with no case sensitivity. The file names are long file names, but the logical "file_name.ext" form is used.

Some file systems do not make difference between lower and upper case characters (Windows 95) and some of them convert all characters to lower or upper case (DOS). Some file manager program (Norton Commander) display all characters in lower or upper case, for example all directory names are printed in upper case letters and all file names in lower case letters.

WARNING! Do not use any program changing the file names (for example DOS programs with no long file name support). If upper or lower case characters are converted, the source files will not make under UNIX.

All header and source files must be started with 'r' to identify the company. The test and example programs have different prefixes: s - Sample and t - Test. For example the rStr_c class is defined in rStr.h, documented in rStr.htm, implemented in rStr.cpp, tested by tStr.cpp and the sStr.cpp is a short exampe program.

The directory structure is designed to support multi platform development, easy and quick archiving, and delivery of the programs on different levels (binary, library with headers, documentation and examples, full source). All projects are collected under the same directory, generally in "/prj". A subdirectory is created for every project under this directory ("/prj/rIDE", "/prj/rMPL"). This directory is the directory of the project.

Source files, include files, documentation, binary files and the compiler generated files are stored under different subdirectories in the project's directory. The "src", "inc", "doc", "smpl" and "test" directories must be saved while archiving, the "_obj", "_lib" and "_bin" directories contains only files generated by the compiler or linker.

It may be useful to put the "_obj", "_lib" and "_bin" directories to a local drive and keep the source directories on the server. In this case "_obj", "_lib" and "_bin" directories will not be under "/prj".

srcsource code (*.c, *.cpp, *.h)
incexported include files (*.h)
docdocumentation (*.htm)
smplexample programs
testtest programs
_objtemporary files (*.obj)
_liblibraries (*.lib)
_binexecutables (*.exe, *.dll)

Under these directories may be further subdirectories for different platforms, libraries and products. The platform dependent parts must be separated in subdirectories named from the actual platform (for example: w32, zApp, owl, mfc, sun, dec, posix, qnx).

5. Using Header Files

List the include files at the beginning of the file. It is recommended to list the system header files and the program module header files separately. Use the <> "" forms, as they work! Use "" only if the header file may be in the current or the source directory. Use path names to decrease the length of the include directories list, but never use '\' in the path names. Use '/' instead. The compilers accept it on MS Windows and DOS platforms as well.

For example:

#include <mem.h> // memset()
#include <stdlib.h>

#include <rCntnr/rStr.h>
#include <rTypes.h>

#include "local.h"

The comment about what is used from the header file is recommended. All the necessary header file must be listed to ensure, that any source file (including the header files) is compiled independently. Using a header file must not require including any other include file. This makes easier for the programmers to follow the dependencies. The files already included in the header file belongs to the source file do not need to be listed in the source file again.

6. Style of the Source Code

Argument lists

Write the full argument list (including types and argument names) both to the declaration and definition. The argument names describe the arguments, so the code is more readable. If an argument is not used in the function do not include the name to the definition to avoid warnings. The ARGSUSED comments and macros are not portable.

Using braces

The braces around a program block must look like one of these:

   if( 1 == aFlag ) {
      // instructions
   } //if

or:

void
Func(int aParam)
{
   // instructions
} //Func()

The opening brace must be at the end of the line or at beginning of the next line. The program block is idented with one tab. The closing brace must always be in a new line below of the beginning of the first line. The closing braces always have a comment about the opening pair. Generally the first is recommended, but the second version is better, if the line is long or contains comment before the opening brace. For example a simple if statement uses the first version while function implementations uses the second.

Using Parenthesis

The source code must be formatted to highlight the functional and syntactical units of the code. Parenthesis should be placed close to the word they belongs to. For example the parenthesis following the if and switch statements belongs to the keywords and not to the enclosed expression. Therefore

   if( NULL!=pPtr ) {...}
is better then
   if (NULL!=pPtr) {...}
. The second form may means, that the following statement is also proper:
   if pPtr {...}.

When the function argument list is long, or comments required for arguments use the following structure similarly to braces:

void
Function(
   int Arg1, // This is the first argumentum.
   int Arg2  // This is the second argumentum.
) {
   // function body.
} //Function

This structure can be used with 'if' or 'while' statements also.

Comments

Use short comments in the header file to separate different blocks of type, function, constant, and variable declarations. Use short comments to explain what is happening, to explain the programming tricks, or any other notes on the implementation. Do not write comments instead of the documentation! An HTML documentation file should be written about the source.

Another point of view, that the implementation should be explained in comments in the source code, while the answer for the question 'how to use this module' should be in the HTML documentation. The documentation is available for everyone, while the source may be kept confidential!

It is recommended to write short comments:

Other Issues

Put close to the beginning of source line what is important! Editor window may be too small to display the end of line and you always read the beginning of lines first.

Use if( NULL == pData ) or if( !pData ), but never write if( pData == NULL ). Consider what happens, if you mistype the double '=' to a single '='. Always put the constant to the left side of the comparation operators to ensure that mistyping cause compile time error.

When the return value of a function is tested in the if statement the return value should be on the left side of the operator. This is more readable

   if( 0==strcmp(/*a very long argument list is coming here*/) ) {
      ...
   } //if
than this:
   if( strcmp(/*a very long argument list is coming here*/)==0 ) {
      ...
   } //if
Please, consider how do you read the code! First you probably will imagine, that this is an if statement, where two strings are compared, and checked if they are equal to each other. Then you may be interested in the strings.

Don't use private data members. The private data members makes difficult to override the gate functions.

Use gate functions to handle data members.

Write redundant code to find and fix wrong parameters and invalid program states. Write default branch for the switch statement, else branch to the if statements, etc. when those branches should never executed. See rDebug for macros and functions helping to fulfill these requirements.

Do not allocate large structures or arrays on the stack. Put them to the heap and check wheather the allocation is succesfull. Resorce managment with objects is recommended. If the resource (for example a file handle or dynamically allocated memory) is allocated in the constructor and deleted in the destructor, and the wrapper class is created as local variable, the resource will be deleted automatically in all cases. If the allocation is failed in the constructor an exception must be thrown.

Use pharentses around arguments and numbers in macros:

#define Sqr_d( x ) ((x)*(x))

int a = Sqr_d( a - 3 ); // This would not work as it expected without pharentses.

7. Error Handling

For error handling generally exception handling is used in most products of Robot Conrol Software Ltd. See rError for definition of exception classes thrown.

The rDebug library is also designed for handling errors by printing trace, warning, error messages and checking value of variables at run-time.


[ Home | RCS | rIDE | SIMM-Sys | SC | Site-map | Help | Feedback ]

Robot Control Software Ltd. Úrbéres u. 62/A., Budapest, 1028 Hungary; Tel:+36-1 398-0200 Fax:+36-1 398-0202