Programming Standards



C Programming Standards

Introduction

Programming standards help programmers read and understand code. There are several essential standards:

• documentation

• indentation and white space

• modularity

• variable scope

• naming

Documentation

Accurate documentation is essential for others to understand code. Additionally, documentation can help explain more obscure functionality which the programmer might forget.

1 Function Documentation Header

Each subroutine (function) must be documented with a documentation header:

/******************** Name of Function **********************************

function prototype

Purpose:

Explain what the function does including a brief overview of what it

returns.

Parameters:

List each parameter on a separate line including data type name and

description. Each item should begin with whether the parameter is passed

in, out or both:

I Passed in. Value isn’t modified by subroutine.

O Passed out. Value is returned through this parameter.

I/O Modified. Original value is used, but this subroutine modifies it.

Notes:

Include any special assumptions. If global variables are referenced,

reference them. Explain critical parts of the algorithm.

Return value:

List the values returned by the function. Do not list returned

parameters. Remove if void.

**************************************************************************/

Example:

/******************** findName ********************************************

int findName (AddressBook addressBookM[], int iAddressBookCnt, char *pszName)

Purpose:

Searches the address book for the specified name to return the location

(i.e., subscript) of that name.

Parameters:

I AddressBook addressBookM[] Address Book array which is searched.

I int iAddressBookCnt Number of entries in the Address Book.

I char *pszName Name to find in the Address Book.

Notes:

Return Value:

-1 Name not found

>=0 Subscript of where the name was found in the Address Book.

**********************************************************************/

2 Include File Documentation

Each include file should be documented:

/**********************************************************************

include file name

Purpose:

Description of its purpose.

Notes:

Description of any special information around usage.

**********************************************************************/

3 Program File Documentation Header

Each program file should be documented:

/**********************************************************************

Program file name by your name

Purpose:

Description of the purpose

Command Parameters:

Description of the command parameters. These are the parameters to

main().

Input:

Description of input to the program

Results:

Description of what is produced by this program.

Returns:

List the return codes and meanings.

Notes:

Description of any special information around usage.

**********************************************************************/

4 Variable Documentation

Each variable must be described. Above structures, a block of comments should be used to describe the structure.

Example:

/*

** Logical Record Address

** A logical record address is the combination of a physical

** record number and a line array subscript. There can be multiple

** logical records within a physical record.

*/

typedef struct

{

long lPhyRecNum; // Physical Record Number

unsigned short usLineArraySub; // Subscript into Line Array

} LogicalRecordAddress;

char szStudentName[31]; // Student Name

5 Code Documentation

Within the code, document conditional constructs (e.g., if, while, for, switch). Significant or obscure pieces of code should be explained. Comments should be at the same level of indentation as the code. It IS permissble to use "//" comments since they make it easier to comment out blocks of code.

Example #1:

/* calculate the average grade */

for (i=0; i < iNumStudents; i++)

{

sum += score[i];

}

/* Check the number of students to avoid zero divide. */

if (iNumStudents > 0)

dAverage = sum / iNumStudents;

else

dAverage = 0.0;

Example #2:

/* If the current print position doesn't have a full line

** of bytes (because it is near the end of the buffer),

** determine the number of bytes to print.

*/

if (iLineOffset + iNumBytesPerLine > lBuffSz)

iNumChars = lBuffSz - iLineOffset;

Indentation and White Space

Indenting code and including some white space makes code easier to follow.

1 Control Constructs

Control constructs (e.g., if, for, while, switch) need indentation. Indent the statements within these constructs one tab. Braces used to syntactically allow multiple statements should be at the same level of indentation as the control statement.

For an if which is on the else branch of another if, it is unnecessary to indent the else if.

Examples:

/* See if there is an empty location or if it already exists */

for (i = 0; i < iStudentCount && iLocation == -1; i++)

{

if (strcmp(studentM[i].szFileName, pSfmFile->szFileName) == 0)

iLocation = i;

else if (studentM[i].szFileName[0] == '\0')

iEmpty = i;

}

/* if not found, is there an empty? */

if (iLocation == -1)

if (iEmpty >= 0)

iLocation = iEmpty;

else if (iStudentCount >= MAX_STUDENT_COUNT)

printf("!!! Student Array is full\n");

else

{

iLocation = iStudentCount;

iStudentCount++;

}

2 Subroutine Indentation

The declarations and code for a subroutine should be indented one tab. The braces surrounding the code should be in column one.

Example:

char *GetToken(char *pszLine, char *pszToken)

{

char *pcLine; // pointer in input line

char *pcToken; // pointer in new token string

/* Look for a delimiter (space) or end of string */

for (pcLine = pszLine, pcToken = pszToken

;(*pcLine != ' ' & *pcLine != '\0')

;pcLine++,pcToken++)

{

*pcToken = *pcLine;

}

/* Null terminate the token string */

*pcToken = '\0';

/* If token ended with a space, advance line past the space */

if (*pcLine == ' ')

pcLine++;

return (pcLine);

}

3 White Space

White space is used to make blocks of code and comments stand out. It is often useful to show that comments apply to a particular block of code using white space.

Example:

/* Adjust the student record to show that the student is active

** with a declared major.

*/

student.lLastEnrollDate = lCurrentDate;

student.cStatus = STATUS_ACTIVE;

strcpy(student.szDeclaredMajor, szMajor);

/* Update the student record on the database */

rc = UpdateStudent (&Student);

Modularity

Common code or code with a meaningful purpose should be placed in a separate subroutine. Modularity makes code easier to understand (assuming meaningful subroutine names are used). This allows the function to be reused.

In general, subroutines should be less than 50 lines of code. (That does not include header comments.)

Variable Scope

Variables used locally should be declared as local. If the same variable name is used in many subroutines, but its value isn’t shared between the subroutines, it should be a local (not a global: not an external). The use of local variables helps prevent stomping on a variable from another routine.

For flexibility, functions should have parameters to allow definition to vary.

If a large structure is common across many subroutines, its value is shared, and its definition will not vary, global variables can be used.

Naming

1 Variable Names and Data Types

Variable names should begin with a prefix which tells the type for the variable.

|Data Type Meaning |Prefix |Example |

|integer |i |int iInventoryCount; |

|long integer |l |long lRecordAddress; |

|(usually 4 byte) | | |

|short integer |sh |short shRequestQty; |

|(usually 2 byte) | | |

|unsigned short |us |unsigned short usBinaryByte; |

|unsigned long |ul |unsigned long usBitmap; |

|float |f |float fTemperature; |

|(usually 4 byte) | | |

|double |d |double dSalary; |

|(usually 8 byte) | | |

|single character |c |char cInputChar; |

|null terminated string |sz |char szName[30]; |

|string which isn’t null terminated and might contain |sb |char sbBuffer[200]; |

|binary data | | |

|Boolean value |b |int bFoundMatch; |

|stream file |file |FILE fileInput; |

|binary file |fileb |FILE filebInventory; |

Naming convention for structure type definitions::

StructNm name of structure in mixed case

Example:

typedef struct

{

char szStudentNr[10]; // Student Id Number

char szFirstNm[31]; // First Name

char cMiddleInitial; // Middle Initial

char szLastNm[31]; // Last Name

long lGradePoints; // Total Grade Points

long lCreditHours; // Total credit Hours

double dGPA; // GPA (if lCreditHours > 0)

char szMajor[4];

} Student;

Student studentM[50]; // array of students

A pointer should indicate what it points to as part of the prefix. A pointer to a null terminated string should begin with psz.

Variable Names should be descriptive and each word should be capitalized. They should be prefixed with the type. (See above.)

Examples:

char sbPhyRecBuffer[200] // Physical Record Buffer which is a string containing binary data

Student *pStudent // pointer to a Student structure

pLogRecAddr // pointer to a Logical Record Address

usFreeSpaceOffset // Offset to Free Space; this is an unsigned short

int iBadFieldCnt // Count of bad fields

long lBadRecordCnt // Count of bad records

char cInputChar // input character

char *pcInputChar // pointer to input character

int bFoundEOF // true when EOF is Found

char szStudentNm[31]; // student name (which is a zero terminated string)

char *pszStudentNm; // pointer to student name (which is a zero terminated string)

char *psbBuffer; // pointer to binary buffer

FILE *pfileStudentData; // Student Data file (stream)

FILE *pfilebStudentRecord; // Student Record file (binary)

It is so common to use rc as a variable name for return code, it is acceptable. This should be declared as a local.

Iterative variables i (interger) and p (pointer) are also very common and acceptable. Please declare them as locals.

2 Subroutine (Function) names

Function names should be descriptive and each word (except the first) should be capitalized.

determineReorderPoint()

generatePlayingField()

3 Constants

Constants should be defined with #define. This allows them to be changed easily. The names of constants should be all uppercase with underscores separating the words.

#define MAX_PHY_REC_SZ 2000

................
................

In order to avoid copyright disputes, this page is only a partial summary.

Google Online Preview   Download