Coding Style Guidelines

Total Page:16

File Type:pdf, Size:1020Kb

Coding Style Guidelines

Coding Style Guidelines

Introduction

The purpose of standardizing a coding style for a development team or project is to reduce friction in the development process. What does it matter if we name our variables or indent our braces in one way or another? To the perspective of a modern compiler, it obviously does not matter. But more importantly, the discipline of a shared style increases overall efficiency, in terms of readability and understanding of the source code-- not only to teammates and other individuals that may need to understand, review, and debug and maintain others' works, but the author himself returning a year from now to update a project, would benefit. With the time saved from trying to get past unfamiliar styles to understand the intent of each other's source code, we can make more significant improvements to our programs. Now doesn't that sound more fun and rewarding?

It is the intent of this document to provide a guideline to a shared style for our C++ source code. Some of the guides may seem arbitrary, but it is more important to agree upon a single style rather than finesse from the diverse opinions. As a rule, when modifying code that doesn't fit the guidelines set in this document, please either match the different coding style of the function, or modify the entire function to the correct style. Finally, this document shouldn't be etched in stone. As opinions change and the team develops, this document should be periodically brought out and reviewed for changes in content and guidelines.

Please read and follow our guidelines, you will see the benefit. Thank you for being a good development citizen!

Naming Conventions

General Naming Conventions Prefix Examples

Classes C CELEventFrame, CSlide

Interfaces I IMediaControl

Methods Invalidate, OnMouseDown

Private Functions ApplyStyle, Draw

Data members m_ m_valid, m_idleCounter

Static data members s_ s_eventPump, s_topOfStack

Variables curSlp, ghostPat

Global variables g_ g_fOleInit, g_pTypeLib

Constants, Enumerations Package- prefix_ GR_STYLEPLAIN, TX_ALIGNLEFT, W_PANE_NOERASEBG

Type Prefix p Pointer to (32-bit is now assumed; thus no need for lp). pp Pointer to a pointer h Handle to, aka cookie or abstract pointer (illegal to dereference). ref Reference to (eg: when passing parameters by reference in C++). rg Array of (ie: items stored sequentially in memory). Note: rg is often used. z Terminated array of. sz CHAR *,String, C type (ie: array of 8-bit characters, null character terminated) or CString wsz WCHAR *, Unicode string.

1 tsz TCHAR *, Flexible Unicode/DBCS string. vec Vector mat Matrix

Type Indicator s SHORT Signed integer, 16-bit. l LONG Signed integer, 32-bit. us USHORT Unsigned integer, 16-bit. ul ULONG Unsigned integer, 32-bit. b BYTE Non-counting purposes, 8-bit allocation. w WORD Non-counting purposes, 16-bit allocation. dw DWORD Non-counting purposes, 32-bit allocation. i int Scalable signed integer u UINT Scalable unsigned integer fl float Floating point, 32-bit, 6-7 significant digits. d double Floating point, 64-bit, 15-16 signigicant digits. ch CHAR Character, 8-bit. wch WCHAR Character, Unicode, 16-bit. tch TCHAR Character, flexible Unicode or DBCS. fn Function Function: always used with a type prefix (eg: pfn is pointer to function). v void Void: always used with a type prefix (eg: pv is pointer to void). f bool or BOOL f means flag var VARIANT or variant_t

Certain abbreviations have become standard abbreviation Word src Source dst Destination rc Rectangle quad Quadrilateral pt Point tx Text ptr Pointer stat Status or state cmd Command id Identifier wnd Window btn Button sel Select or Selection

Member Function Names

We highly recommend using the following standard prefixes for member function names. Function prefix Type of function

F… Query operations that return a bool

2 Get… Gets a property.

Set… or Put… Sets a property.

Create… Creates or duplicates a C++ object. Use “Duplicate” for a method that duplicates the object Dup… itself. Objects returned by these functions must be disposed with delete.

On… Protected notification methods usually overridden by clients. Where both On and After After… methods are provided, On is called prior to the event, and After is called after.

Draw… Modifier operations (named with active verb phrases). Move…

Swap Swaps the contents of one object with the contents of another in a way guaranteed to succeed and not throw an exception.

Code formatting

Indentation

No Tab character

Make sure all tab character converted to 4 spaces.

Indent level

One indent level is 4 spaces

Indent data declarations and executable statements one level // Example of function definition PCOMMSG ComGetMsg( PCOMSERVER pServer, long lTimeOut) { //--- Data indented same level as code PCOMMSG pMsg;

//--- Code indented one level pMsg = ComReadMsgFromQueue( pServer, NULL, ComWait_c, lTimeOut ); if ( NULL == pMsg ) { ErrReport( “Server connection broken” ); } return pMsg; }

Indent function and data declarations at least one additional level beyond the public, protected, and private keywords. class CExample { //--- public, protected and private functions indented. public: //--- Member function declarations indented at least on additional level CExample(); ~CExample();

3 private: #ifdef _DEBUG void TraceValue( int iValue ); #endif

//--- public, protected and private data members indented. private:

//--- Data declarations indented one level int m_iStoreSomething; };

Indent long function calls pMsg = ComReadMsgFromQueue( aServer, NULL, ComWait_c, lTimeOut );

Brace

Use Braces "{}" to mark the beginning and end of all compound statement aligned vertically with their parent block. while (foo) { if (bar) { Yabba(dabba); } else { foo(); } Xyz(abc); }

Statements that have bodies should put those bodies on a separate line and braces should always be used – even if the body is only a single line. for( ) { }

if ( ) { }

4 else if ( ) { } else { }

White Spaces and line breaks

The maximum line length is 80 characters

Leave at least one space between a binary operator and each of its operands; use extra spaces to align operands if this improves readability: iA = iB + iC; iMinimum = -iAmplitude; cLetter = *pChar; flY = ( flX * flSlope ) + flY0; x = ( pEvent->m_iButton == iButtonPress ) && ( 1 == pEvent->m_iButton );

Never end a line with a space or tab.

Have a blank line between variable declarations and code. BOOL FFoo(void) { BAR bar1, bar2; int cbar; // There is a blank line below.

cbar = Bar(&bar1, &bar2); return cbar == 0; }

Spaces are always AVOIDED in the following places:

Between the function name and the left parenthesis, e.g. “Foo (”

Between a pointer and the variable it modifies, e.g. “FOO * pfoo”

Next to arrows, e.g. “a-> b”;

Next to variable/dot combinations, e.g. “a. b”

Spaces are always USED in the following places:

Around keywords, e.g. “if (...)” and never “if(...)”.

Between argument/variable combinations in parentheses, e.g. “(a, b, c)”

Between a type and a pointer, e.g. “FOO *pfoo”

Surrounding equals signs, e.g. “a = b;” and never “a=b;”

5 In summary, spaces are placed as in English (e.g. space after comma, no space after parentheses, space after keywords, space before and after most operators).

Never have multiple statements on one line like a = 1; b = 2; // bogus if (fFoo) Bar(); // bogus

Labels are always on lines by themselves. LFoo: a = 1; // bogus

Syntax

Common Types

Use the built-in types (short, int, long, etc.).If it requires limit types used, it’s recommend to redefine all types used in a common header file.

Structs struct POINTD // use this { REAL X; REAL Y;

}; typedef struct tagPOINTD // Do not use this { REAL X; REAL Y;

} POINTD;

Const-correctness

Use const wherever an item won’t be changed. HRESULT Compress(BYTE *pbOut, DWORD *pbOutLen, const BYTE* pbSrc, const DWORD dwSrcLen);

Type casts

Use explicit typecast force compiler and programmer to more verification. int *ptr = (int *) malloc(xyz); // DON’T DO THIS char *device = (char *) 0xf0000123; // DON’T DO THIS int myInt = (int) myConstInt; // DON’T DO THIS

Use these: int *ptr = static_cast(malloc(xyz)); char *device = reinterpret_cast(0xf0000123); int myInt = const_cast(myConstInt);

Function definitions

6 Must be defined with the return type VOID RandomObject::DoSomething( INT x, Blob *blob ) { blob->Glob(x); }

In function declarations (prototypes), the following is allowed if it fits on one line. INT ComputeArea(INT x, INT y);

Function calls

If the call fits on one line: answer = GetAnswer(x, joe, blob);

Otherwise, put each parameter on a separate line, indented one level: MyFunctionWithLongName( sqrt(x*x + y*y), *(ptr + 64) – 30 );

Comments (Clear and necessary)

You can simply copy and paste the following comments before file header and functions to your code.

File headers /*****************************************************************************\

Zhejiang University Copyright (c) 2004 Zhejiang University

Module Name:

An unabbreviated name for the module (not the filename)

Abstract:

Description of what this module does

Notes:

[Optional] Additional notes about this module - things that may help the reader of this code later on. Examples are: algorithm description, special case conditions, references, etc.

History:

7 Created on mm/dd/yyyy by email-name Modified on mm/dd/yyyy by email-name [Optional] history description

\*****************************************************************************/

Section separators //------… a commented one

//------// Buffer manipulation routines //------

Function headers /*****************************************************************************\

Function Description:

Description of what the function does

Arguments:

[ | OUT | IN/OUT] argument-name - description of argument …

Return Value:

return-value - description of return value or NONE

History:

Created on mm/dd/yyyy by email-name

\*****************************************************************************/

Classes definition

Please follow this example:

#define IN // Nothing but a sign show the input/output parameters #define OUT class CMyClass {

8 public: DWORD Compress(OUT BYTE *pbDest, // recommend use “IN” and “OUT” OUT ULONG*puDstLen, // to indicate input and output parameters IN const BYTE *pbSrc, IN const ULONG uSrcLen );

// short inline function can be inside class decalration inline GetByte(const ULONG uIndex) { return m_pBuffer[uIndex]; }

// Recommend use reference parameters to get output instead of pointer HRESULT GetHeaderInfo( IMAGE_HEADER& refImgHdr ); private: IMAGE_HEADER m_ImgHdr; // Data members should never be public public: virtual HRESULT Display(); // Be careful with virtual functions

// const for function means member data is not modified. // highly recommended const VOID Dump();

// Recommend use the two stages initialization BOOL Init(); // HRESULT can return more status BOOL Free();

CMyClass(); ~CMyClass(); }

Source Code File Structure

Here is the general format of the source code file for a class implementation: file header #include directives (private to implementation) #defines (private to implementation) typedefs (private to implementation) global variables internal functions exported functions "methods" implementing messages class initialization routine main routine (in an app class)

Here is the general format of the source code file for a non-class implementation: file header

9 #include directives (private to implementation) #defines (private to implementation) typedefs (private to implementation) global variables internal functions exported functions

Implementation Issues

One time include in header files

Headers should be protected with #ifndef…#define…#endif blocks for inclusion safety.

Sample.h #ifndef _GDIPLUS_H #define _GDIPLUS_H … … #endif // _GDIPLUS_H

Or you can simply use #pragma once at the beginning of file

Function length

Functions should be fewer than 100 lines long unless structure or performance requires a longer function. In general functions should be even shorter, with sub-functions created as necessary.

Use of NULL as flag

1 - Explicitly put NULL in any value test: //Don’t do this: if (pInterface) { } // do this instead if (NULL != pInterface) { }

2 - Always initialize and reset the pointer to NULL. This ensures that you will never be accessing a stale pointer // don’t do this if (NULL != pInterface) { pInterface->Release(); } // do this if (NULL != pInterface)

10 { pInterface->Release(); pInterface = NULL; }

Parameter Validation

Every public interface method must validate input parameters. HRESULT Foo( PBYTE pbSrc ) { ASSERT( NULL != pbSrc ); ... }

// TODO & // REVIEW Indicator

// TODO & //REVIEW indicator is a mark in comment to show the work should be done or reviewed later. It’s a good habit remind yourself and other colleagues before shipping in team project. Before shipping, all the // TODO should be removed (the tasks should be done or change // TODO to // REIVIEW)

Format: // TODO [task owner][(writer)]: Task description

Examples: // TODO: cleanup … The following is BARNWL tells GANGCH write cleanup code later // TODO: GANGCH(BARNWL): cleanup

11 Coding Style Checklist

1 Classes

Declaration

1.1 Declare all class members explicitly as public, protected, or private, in groups in that order.

1.2 Do not declare public data members in classes. Use inline accessor functions for performance.

1.3 Virtual functions have overhead, so don’t use them unless you really should.

1.4 An overridden virtual method is explicitly declared virtual for clarity.

1.5 A destructor in a base class should always be virtual if polymorphism is intended.

1.6 Never hide expensive work behind an operator. If it’s not super efficient then make it an explicit method call.

1.7 Don’t use inheritance just because it will work. Use it sparingly and judiciously.

1.8 Don’t use multiple inheritance.

Constructor and Destructor

1.9 Never declare a global instance of a class that has a constructor.

1.10 Do not do expensive work in a constructor.

1.11 If you do make a constructor, make sure to initialize all data members.

1.12 A constructor should never fail. Do memory allocations and other potential failures in a FInit or Create method.

1.13 A destructor should never fail

2 Other C/C++ Issues

2.1 Avoid allocating class instances on the stack and passing them by value. Use new and delete, and pass them by

pointer.

2.2 If resources are freed before destruction, make sure the fields are reset (e.g. set pointers to NULL) to prevent multi-

free.

2.3 Use const or enum instead of #define for constants when possible.

2.4 Use const to mark read-only pointer parameters (what the pointer points at, not the pointer itself).

2.5 Don't use default arguments.

2.6 Minimize global variables.

2.7 Use inline functions instead of #define macros when possible

2.8 In functional macros, enclose all argument instances in parentheses “( )” as well as the entire expression if necessary.

2.9 Functions that return pointers but can fail should return a BOOL and return the pointer in a parameter.

2.10 DLL-exported data should be avoided, but must use extern "C" if needed.

2.11 Use the macros defined in OLE’s objbase.h where appropriate for C/C++ declarations, especially COM-style

interfaces.

3 Source File Organization

3.1 Filenames use prefix denoting the major feature team (e.g. “tb” for Toolbars), then <= 6 more characters.

12 3.2 Use one-time include in header file, e.g., #pragma once or #ifndef FOO_H, #define FOO_H , #endif //

FOO_H

4 Basic Data Types

4.1 Use the following common basic data types: void, int, BOOL, UINT, BYTE, CHAR, WCHAR, USHORT, WORD,

SHORT, ULONG, DWORD, LONG, HRESULT

4.2 Use other types already defined by Windows (e.g. RECT, POINT) when possible, especially in exported interfaces.

4.3 Use "BOOL", "int", or "UINT" in most bitfields, unless size is important, then use a size-specific type such as

USHORT.

4.4 Use flat 32-bit pointers everywhere (declared using just plain “*”).

5 Naming Conventions

5.1 Use Hungarian naming conventions. Invent new tags and use them consistently where appropriate to preserve

abstraction.

5.2 Check tags and prefixes defined in the tables of naming convention section

6 Formatting Issues

6.1 Each file starts with a standard file header comment

6.2 Make sure your editor indents using 4 space tabs.

6.3 Keep line length within 80 characters.

6.4 Indent correctly in declarations and statements including: function, class, switch and if

6.5 Place spaces as in English (after keywords and commas, not after open parentheses, between many operators).

6.6 Write comments necessary, simple and clear

6.7 Use a blank line between blocks of code separated by a summary comment.

6.8 Precede function prototypes with a comment describing the function in complete sentences, mentioning each

parameter.

6.9 Use “// TODO: comment” to mark incomplete code, and “// BUG: comment” to mark wrong code.

6.10 Check everything referring to code formatting

13

Recommended publications