Search This Blog

Thursday, March 18, 2010

C Coding Standards : Part 3 (The Last Part)

//--------------------------------------------
// Creation Date -- 18th March, 2010
// Last Revision -- 14th April, 2010
//-------------------------------------------

5. Comments:

5.1 File Headers:
Every file--both header and source files--should begin with this standard banner comment:
//-----------------------------------------------------

// File: foo.cpp (or .h)

//

// Desc: This is the description of the file.

// Long descriptions should be

// justified/indented like this.
//

// Any notes or multiple paragraphs are

// formatted like this.

//

// 11/2/2000 - subhab – Started this file

// 12/8/2000 – subhab – Fixed bug 12345

// in GetName() method

//

// Copyright (c) 2009-2010, SUBHA Pvt. Ltd. All rights

// reserved.

//------------------------------------------------------

5.2 Function and Method Headers:
Any function with non-obvious functionality, complex behavior, or a large list of input parameters should use a comment like the one below. It is optional for all other methods.

//--------------------------------------------------
// Name: foo()
// Desc: This method does nothing but return TRUE.
// It's just here to show what
// a function header should look like.
// Parameters:
// Parameter1 String used as input
// Parameter2 String used as output
//--------------------------------------------------

5.3 Structure Headers:
It is strongly recommended that all non-trivial structures have a header such as the following:

//--------------------------------------------
// Name: structure stNothing
// Desc: This structure does nothing.
// It's just here to show what
// a structure header should look like.
//--------------------------------------------

5.4 Section Dividers:
Each major section of code should be divided by a header such as:

//-------------------------------------------
// Global data
//-------------------------------------------

5.5 Source Comments:
The use of the // comment format is preferred over the /*…*/ format.

5.5.1 Inline Code Comments:
Inline comments should be included on their own line and should be indented at the same level as the code they are commenting on.

For example:

if (NULL == pFoo)
{
// The pointer is null, we cannot continue.
return E_POINTER;
}

Inline comments are permissible on the same line as the actual code only when giving a brief description of a structure member variable, or parameter. In this case it is a good idea to align the comments for all variables.

For example:

struct stFoo
{
int m_iCount;
// used to store the reference count
DWORD m_dwSeed; // store the random seed value
};

5.5.2 Commenting Out Code:

It is preferable to use #if 0 over /*…*/ to comment out code you don’t want compiled. The first style can be safely nested whereas the second cannot. Test against ‘0’ instead of an undefined value because someone might just define that value.

#if 0
// correct, always works

#ifdef NOTDEF
// bad – might fail


6. Programming Considerations:

6.1 Performance Considerations:
The following are merely recommendations but ones that will serve you well if you follow them.

6.1.1 Branch Prediction:
Code your if statements so that the most likely case is the true evaluation. The Pentium processor reads the instructions ahead and must flush a lot of work to branch around the true case. Intel’s documentation can provide more information on this subject.

6.1.2 Postpone Local Variable Definitions:
Define a variable right before you use it, not at the top of the block. If you happen to return before getting to where the variable is used, you’ll save a constructor and a destructor call. It may also ease stack use, lessen register pressure, etc.
The exception is when you have an object with a constructor inside a loop. In this case, it may be advantageous to declare the object right before the loop so that it does not have to be constructed and destructed each loop iteration.

6.1.3 Avoid Header File Bloat:
The unnecessary inclusion of header files can cause compilation times to increase, sometimes by a factor of 2 or 3. You can avoid header bloat by forward declaring classes and structs rather than including the header file where they are defined.
It can also be beneficial to use precompiled headers if you have a lot of source files and they are all including the same headers (like stdio.h).

6.1.4 Data Locality and Alignment:
Define the order of structure/class members with the following principles in mind:
largest types first – a fetch of N bytes is fastest by far if the memory is at 0 == (addr % N). If you define some odd BYTE or short members first, the compiler must either add padding to these small members to get your later double members aligned, or it must generate multiple reads to get the doubles. Adhering to this principle, coincidentally, also gets you the smallest struct. Interestingly, same is true of local variables and parameters.

void MyFunc(double dbl, char ch) // Misaligned dbl!
{
if( ch > g_ch ) {
g_ch = ch;
}

if( dbl > g_dbl ) {
g_dbl = dbl;
}
}



// Same function executes 4-5% faster when dbl is aligned.
// _stdcall, _cdecl, _fastcall are all right-to-left ordered

void MyFunc( char ch, double dbl )
{ … }


Members that you access frequently or that you always access a short time from each other should be located near each other in your struct.. The cache lines are 32bytes wide and all memory is cached 32bytes at a time, so if your struct is larger than this, you want to avoid having to fill two cache lines if the members you need could have occupied one.
If you plan on having arrays of structs, consider adding deliberate padding at the end such that no element in the array will begin misaligned or will span a cache-line unnecessarily.

struct STWillMakeUpAnArray
{
double dblKey;
// bytes 0-3
float fltX; // 4-7
float fltY; // 8-11
short iZ; // bytes 12, 13 only!
BYTE pad[2]; // Without this, we misalign
// every odd element’s
// dwKey, fltX, and fltY members!
// Arr[3], and others, require 2
// cache-lines, hurting random access.
};

6.1.5 Temporaries and Copies:
Pass-by-Reference can be an easy solution to the problems with pass-by-value and return-by-value.

bool IsFontBold(int iCheck) // Don’t do this
{
return iCheck > gc_iThreshold;

}

inline bool IsFontBold(int &iCheck) // Good!
{
return iCheck > gc_iThreshold;
}


You can achieve the same with pass-by-pointer, the differences being pointers can be NULL, pointers can be reassigned (well, const BigFontClass * const pMyFont couldn’t…), pointers cause ambiguity about who owns the memory, while references have none of these problems. If you call IsFontBold( * pMyFont), you’d have better checked pMyFont for NULL before making the call!
Return-by-value does allow a clever compiler optimization for anonymous temporaries; the compiler has an excellent chance of constructing this object directly into the memory, whereas if a local variable were created first, there would be 2 copy-constructor(/operator=) invocations.


int MyFunc( int ia, int ib )
{
return (ia+ib);
}

int iSum = MyFunc( i1, i2 );


6.1.6 Size == Performance:
In the vast majority of code, the users’ perception of the performance of the code is determined by the binary size. Writing smaller code will improve load times, increase cache performance, etc.

6.2 Clean Coding Style:

6.2.1 Const and Volatile:

Use const liberally. If a variable will not be changed in a function, make it const. If a method will not be changing any member variables, make the function const. This will allow the compiler to catch potential errors which would otherwise be difficult to track down. Use const member functions if possible.


The purpose of volatile is to force an implementation to supress optimization that could otherwise occur.
For example, for a machine with memory-mapped input/output, a pointer to a device register might be declared as a pointer to volatile, in order to prevent the compiler from removing apparently redundant references through the pointer. Except that it should diagonose explicit attempts to change const objects, a compiler may ignore this qualifier.


6.2.2 Test for the Error Case, Not the Success Case:
Code is much more readable if blocks are kept to a minimum. One way to do this is to check for the error case up front rather than checking for the success case and entering a block if successful.


// Do Not Do This
bool MyFunc(int * pInt)
{
if (NULL != pInt)
{
CFoo pFoo = new CFoo();
if (NULL != pFoo)
{
//do something here
}
else
{
return false;
}
}
else
{
return false;
}


// instead, prefer this
bool MyFunc(int * pInt)
{
if (NULL == pInt)
{
return false;
}
CFoo pFoo = new CFoo();
if (NULL == pFoo)
{
return false;
}
// do something here
}

6.2.3 Limit Exit Points From Functions:
Having more than one exit point in a function or method which allocates memory or increments reference counts risks memory leaks. It is difficult to account for all of the various delete or release combinations required if the function exits early. Even if all of these cases are handled, maintenance of the code can be cumbersome at best and fraught with peril at worst. It is therefore recommended that you limit the number of exit points from a function.
Many people will use goto statements to accomplish this. This is not recommended. The use of goto wreaks havoc with the compiler’s ability to optimize code. It cannot be assured of the execution path and so foregoes much of its optimization


6.2.4 Functions Should Be Short:
As a general rule, functions should be able to fully fit onto the screen at one time. Longer functions are harder to maintain and harder to understand. Functions longer than approximately 30 lines should be examined to see if they can’t be broken up into a series of smaller functions. This isn’t a hard and fast rule, but will produce more maintainable code if it is followed.


Monday, March 8, 2010

C Coding Standards : Part 2

//----------------------------------------------
// Createtion date - 08th March, 2010
// Last revision - 09th March, 2010
//----------------------------------------------
4. C Coding Practices:
4.1 Using typedef:
4.1.1 Structs and Enums
The use of typedef with structs and enums is common in C code. Use it to define the structs and enums type which are already defined.
// Correct definition of a struct
struct Foo
{
int x;
int y;
};

typedef struct Foo* pFoo;
// Incorrect definition of an enum
typedef enum _Bar
{
FIRST,
SECOND
} Bar;

Be cautious, the ‘typedef’ directive DOES NOT CREATE A NEW TYPE. It is a compiler level #define. As a result, the following produces a linking error:
// These two typedefs produce the same output for the compiler
typedef int A;
typedef int B;
void MyFunc( A a );
void MyFunc( B b );

(These produce the linking/compiler error that the function "void MyFunc( int )" was defined twice, since both A and B are ‘int’s and are not different types.)
DO NOT OVERUSE IT JUST FOR FUN.

4.1.2 Pointers to Functions
Typedefs are permissible when using pointers to functions. They make the code much cleaner and easier to understand.
int func(int i, bool b);
// Function prototype, defined somewhere
int (*MyFuncPointer) (int, bool);
// Pointer to function
MyFuncPointer = func;
// Assign to the pointer;
(*MyFuncPointer) (2, true); // Call
MyFuncPointer(3, false);
// Call
Do not declare pointer to function as
int *MyFuncPointer(int, bool);
Here, MyFuncPointer is a function which returns pointer to integer.

4.2 Comparison:
4.2.1 Constant Comparison

The constant member of a comparison should be placed on the left side of the comparison. This will cause the compiler to issue an error when you accidentally use = instead of ==.
if (0 == x) // good
if (x == 0) // bad bacause could become if (x = 0)

4.2.2 Pointer Comparison
It is recommended that NULL be used to explicitly test against pointers rather than the not (!) operator.
int *p;
if (NULL != p)
{
...
}


4.2.3 Boolean Comparison
Do not test bool return values for equality with true. No assumptions should be made about the bit pattern representing TRUE. Many functions assume that anything non-zero is true. Comparisons for equality of false are permissible because false is always 0. Comparisons should be made for equality or inequality with false or should use the not (!) operator.

4.3 Ternary Operators:
Try to limit the use of the ternary operator (?:) to the assignment of simple values, not complex expressions. Use of nested ternary operators is discouraged.

4.4 If Statements:
In cases where a single statement forms the if then or else clause of an if statement, it is required that the statement be bracketed as a compound statement.
// This is preferred
if (0 == y)
{
y++;
}

// This is not allowed
if (0 == y)
y++;
Else statements should be placed on the next line after the closing brace of the if statement. They should not be on the same line as the closing brace.
if (0 == y)
{
y++;
}
else
{
y--;
}


4.5 Sizeof Oprators:
The sizeof operator should be used with parenthesis around the object of the operator.
int y = sizeof(x); // Correct
int y = sizeof x;
// Incorrect

4.6 Bitwise Operators:
All expressions involving bitwise operators should be parenthesized.
i = ((a & 0xFF) >> 2);

4.7 Named Constants:
Named constants should be declared using all upper-case letters. #define’d values should be avoided if at all possible. It is preferable to declare a const variable over using #define. Const variables allow the compiler to do type checking whereas #define does not. A global ‘const’ has a ‘static’ storage class by default (it is a local variable that is discarded if not used).
// Prefer
const int BLACK = 3;
// to
#define RED 4

4.8 Switch Statements:
4.8.1 Clearly Mark Intentional Fall Through
A common bug with switch statements is failing to break out of the statement after executing the intended code. Each code block in the construction should be ended with a break statement. In the rare case where you intend to execute the following code block, you should comment as follows:
switch (variable)
{
case 1:
x = y + 1;
// Intentionally Falling Through
case 2:
y++;
break;
}


4.8.2 Indentation for Switch Statements
The layout of a switch statement should be as follows:
switch (variable)
{
case ONE:
. . .
break;
case TWO:
. . .
break;
default:
. . .
break;
}

to be continued...

Wednesday, March 3, 2010

C Coding Standards : Part1

//--------------------------------------------------------
// Creation date - 03rd March, 2010
// Last revision - 03rd March, 2010
//--------------------------------------------------------

1. Introduction:
I konw all of you know about C coding and many of you are good in that. So, what the hell is the CODING STANDARD! What shall I get from this black characters written down?
It is quite natural, those above things are giving you a itchy feeling in your brains. Let me explian. When I was merely a student of computer application, writting codes and running that properly and perfectly was enough for me. But after all these years of coding, I understand just working code is not enough. You need to maintain some standards in your coding style.
This makes your codes more orgnaized and readable (edible also), which makes your (and other coders) life easier in future.

2. General Coding Style:

2.1 Tabs:
The editor should be configured to save tabs as four spaces. This ensures that all fixed-character-width (where all the characters have same width) editors view the code in the same way.

2.2 Line Length:
No line should exceed the width of the typical source code editor. This is typically around 80 characters. Lines should not be allowed to "wrap" but rather should have line breaks at the end of each one.

2.3 Statement Indentation:
Each time a new scope is introduced, either through the use of a compound statement or the introduction of braces, the statements contained in the new scope should be indented 4 spaces (1 tab).

2.4 Braces:
2.4.1 Openning Braces
Wars have been fought over whether or not to place the opening brace on the same line as for, if, etc. statements (K&R style) or on the following line (Allman style). Either style is acceptable but it should be used consistently within a code file. The K&R style allows the code to be more compact and thus more eadible, but the opening brace is easily overlooked. The Allman style makes the opening and closing braces clearly visible (what I prefer).

// K&R Style
while (x <= 5) {
printf("Hello");
}
// Allman Style
if (x > 5)
{
printf("Goodbye");
}

2.4.2 CLosing Braces
It is strongly encouraged that closing braces are accompanied by a comment which indicates what the brace is closing. If there is a significant amount of code or multiple levels of braces surrounding the opening and closing braces, this comment is required.

For Example:
for(int i = 0; i <>
{
...
} // for i

2.5 Use of Blank Lines:
It is acceptable to use a single blank line to separate areas of functionality within a method. No more than a single blank line should be used within the body of a method. Two blank lines should be used to separate the end of one method body from the beginning of another.

2.6 Always Check Return Codes:
If the unexpected happens, it can be hard to track down if code isn’t paying attention to return values of the called functions. For this reason, every function or method that has a return code should have its return code checked by the calling function. This could save hours of debugging time if the function does fail. Any function call where the return code is not checked, should include a comment explaining why the return code is being ignored.

3. Naming Conventions:

3.1 Variable Names:
3.1.1 Naming Your Variables
Variables should be descriptively named (should be nouns or compound nouns). Single-character variables should only be used as counters (i, j) or as coordinates (x, y, z). Except for type or scope decorations, each word should be Capitalized. In the case of single-character variables, capitalization is not expected.
The variable names should be prefixed with data-type. I am giving here a list for it (Please knock me, if I miss any data-type).

short - s
int - i
float - f or, flt
double - dbl
char - ch
unsigned - u
pointer - p

// Good Variable Names
int iNumberOfNodes;
char * pchUserName;

// Bad Variable Names
int n;
// cannot tell what n is used for
char * Something; // name is not descriptive

3.1.2 Scope Designation
The scope of a variable should be discernable from the name of the variable. The following decorations should be used:
g_ is used for global variables (should be rare).
No decoration indicates a local variable.

3.2 Function and Method Names:
Function and method names should be in the form of a verb or verb-noun structure as in Print() or PrintName(). The first character in each word should be upper case and no underscores should be used.
to be continued...