Home Software Docs Tutorials Demos Databases Dictionaries Models Research Support Mailing Lists What's New
You are here: Standards / General / Tutorials / Software / Home  

 
  Programming Style
black fading line


Programming style is the one thing which varies the most from programmer to programmer. However, working in a group environment requires that each member of the group stick to common coding practices. Our goal is that each member of our group write code which is stylistically indistinguishable from the other members' code. This is particularly important in a university environment since code is often passed from generation to generation of students in our group. So in the ISIP style guide we try to remove as much "creative" freedom as possible from the programmer and, in doing so, provide consistency for our sponsors.

Listed below are points which should guide the programmer in writing code to fit the ISIP Standard.


Return to C++ Programming Standards Page

General style issues

Comments: Commenting is done using C++ style comments with two front-slashes followed by a space and then a line of text. Comments also follow some basic conventions.

  • The last line in a comment-block should be a blank comment line.

  • Lines of code should come after the comment block without blank lines in between.

  • The first line in a comment block should be preceded by a blank line.

  • All characters in comment lines should be lower-case.

  • Here is an example of a valid comment
           // provide debugging information
           //
           if (debug_level_d == ISIP_DEBUG_FULL) {
           fprintf(stdout, " temp filename = %s\n", tmp_string);
           }
           
Naming Conventions

Constant names: Constant names follow the same rules as variable names with a few additional constraints.

  • All letters in constant names are capitalized.

  • All constant names are multi-word with each word being separated by an underscore.

  • The first word in constant names is an abbreviation for the class or program for which the constants were defined.

  • There is no distinction made between class constants or any other type of constant (i.e. the "_d" is not necessary.)

  • Only constants defined in integral_constants.h should be prefaced by ISIP.

  • Examples of valid constant names
           // constant for the sof class
           //
           #define SOF_CLASS_NAME (char_1*)"Sof"
           
           // constants for the fourier transform class
           //
           #define FT_FH_NAME (char_1*)"fh"
           #define FT_DEFAULT_ORDER (int_4)"1024"
           
Class names: Class names in the ISIP Standard follow the same rules as variable names with a additional constraints.

  • The first letter in the class name is capitalized. This is the only letter in the name which is capitalized even if the class name is a multi-word.

  • Class names should accurately describe the object they are defining.

  • The first three of the following class declarations are incorrect. They are followed by the preferred form.
           // this one has a lower-case letter for the first character
           //
           class fourier_transform {
           
           // this one is not multi-word and uses an upper-case
           // in an improper location
           //
           class FourierTransform {
           
           // this one is not descriptive enough
           //
           class Fourier {
           
           // this one follows all of the rules for naming classes
           //
           class Fourier_transform {
           
Program names: Program names in the ISIP Standard take the following form:

verb_noun
  • The verb portion of this program name indicates what type of action(s) is performed.

  • The noun portion of this program name indicates the type of data that the action is performed upon.

  • Below are two examples of incorrect program names and their corrected form
           fft_analysis		// not preferred: not in verb_noun form
           analyze_fft		// preferred
           
           find			// not preferred: noun portion is missing
           find_noun_form	// preferred
           
Method and function names: Method and function names follow the conventions below.

  • Names must describe what task the function performs.

  • Names must have all lower-case letters.

  • Words in multi-word names are separated by underscores.

  • All names are suffixed by "_cc".

  • Some examples of function names follow
           // this method sets the delimiter character used in an ascii sof file
           //
           logical_1 Sof::set_delimiter_cc(char_1 value_a) {
           
           // this method replaces all environment variables and other such
           // things in a string with their equivalent expansions.
           //
           logical_1 Sof::expand_cc(char_1* o_name_a, char_1* i_name_a) {
           
           // this function gets the command-line parameters for a utility
           //
           logical_1 get_params_cc(int argc_a, char** argv_a,
           int_4& mode_a, int_4& dbg_level_a) {
           
Operations

Mathematical and boolean operations:

  • All mathematical operations and comparisons should follow the form:
           <left_operand> <operator> <right_operand>
           
    for example
           int_4 i = (int_4)1;
           
           int_4 j = (int_4)2;
           
           float_4 k = (float_4)0.0;
           
           i = i * y;
           
           k = (float_4)(j * i);
           
           i = (int_4)((float_4)j + k);
           
           for (int_4 i = 0; i < length; i++) { 
           
  • All operators should be bordered by a single space on both sides.

           // an example.
           //
           if (name<=SENT_NAME) {	// not preferred 
           if (name<= SENT_NAME) {	// not preferred 
           if (name <=SENT_NAME) {	// not preferred
           if (name   <=   SENT_NAME) {	// not preferred 		       
           if (name <= SENT_NAME) {	// preferred 
           


  • Parentheses should be used as needed to override precedence or for clarity. When in doubt, it is better to have too many parentheses than too few.

  • Use casting to explicitly set types at all times.

  • If possible, do not split comparisons across lines.

  • When performing compound boolean operations, always use parentheses to separate the different comparisons. This provides much greater clarity in your code as well as making it easier to debug.
           if (((i < k) && (j == 10)) || (k >= j)) {
           
  • Boolean tests should not explicitely compare against Integral::TRUE and Integral::FALSE. For instance,
           if (flag == Integral::TRUE) {
           
             // exit gracefully
             //
             flag = ISIP_FALSE;
           }
           
    should be replaced by
           if (flag) {
           
             // exit gracefully
             //
             flag = ISIP_FALSE;
           }
           
    Also, most functions which return boolean return a logical error status. This means that if they operate correctly, they will return Integral::TRUE, else Integral::FALSE. To wrap a method for error handling you should use
           if (!processData(data)) {
    
             return Error::handle(name(), L"method-name", ERR_PROCESS);
           }
           
    rather than
           if (processData(data) != Integral::TRUE) {
    
             return Error::handle(name(), L"method-name", ERR_PROCESS);
           }
           
  • It is not acceptable to use a non boolean value for a logical expression. While C++ allows that the value 0 is false and all other values are true, this is not good programming practice. If you want to branch on a numeric value, explicitely state this in a logical expression, i.e. while (i != 0).

Includes: There are two different ways to include header files in code: using angle brackets and using quotes.
#include <integral.h>
#include "fourier_transform.h"
Use of quotes should be reserved for header files which reside in the same directory as the one doing the include. All others should use angle brackets.

Loop structures and branch statements

Method and function types: All methods and functions should have some return type unless it has to be defined to interface some external software. Most often the type will be a logical_1. This lets the user know if the method or function was successful (ISIP_TRUE) or unsuccessful (ISIP_FALSE). This is what we call "exiting gracefully" as shown in the code below.
// return: a logical_1 value indicating status
//
// this method sets the delimiter character used in an ascii sof file
//
logical_1 Sof::set_delimiter_cc(char_1 value_a) {
delimiter_d = value_a;

// exit gracefully
//
return ISIP_TRUE;
}
Of course, functions or methods can also return any type of data. Some examples of various methods are shown below.
// return: the last dtmf key hit on this channel (if not cleared)
//
char_1 Channel::get_last_dtmf_cc() {

// exit gracefully 
//
return dtmf_d;
}

// return: the last dtmf key hit on this channel (if not cleared)
//
VCB* Channel::get_vcb_cc() {

// exit gracefully 
//
return &vcb_d;
}
Default Arguments: If the default argument is an integral type, use the standard C++ notation for default arguments, specifically
       // assignment method
       //
       boolean assign(byte* data, long encoding = SysChar::DEF_ENCODE);
       
Notice that this effectively creates two versions of the assign method,
       // assignment method
       //
       boolean assign(byte* data, long encoding);
       boolean assign(byte* data) {
           return assign(data, SysChar::DEF_ENCODE);
       }
       
The problem arises when the argument you wish to make default is a class, this framework does not work. The solution is to put both methods in the same method file. The
   
   
    Help / Support / Site Map / Contact Us / ISIP Home