C++ CODING STANDARDS GlobalSCAPE, Inc. Last Update: 09 June 2000 (GTH) Table of Contents TABLE OF CONTENTS ......................................................................................................................... 1 INTRODUCTION..................................................................................................................................... 1 SOURCE FILES ....................................................................................................................................... 1 STRUCTURE AND NAMING CONVENTIONS ................................................................................................ 1 FILE NAMING ........................................................................................................................................... 1 COMMENTS............................................................................................................................................. 2 FILE COMMENTS ...................................................................................................................................... 2 CLASS, METHOD, AND FUNCTION COMMENTS ........................................................................................ 3 INCLUDE FILES...................................................................................................................................... 5 ASSIGNING NAMES............................................................................................................................... 6 STYLE ....................................................................................................................................................... 7 CLASSES .................................................................................................................................................. 7 FUNCTIONS .............................................................................................................................................. 7 COMPOUND STATEMENTS ........................................................................................................................ 8 FLOW CONTROL STRUCTURES ................................................................................................................. 8 QUALITY FACTORS.............................................................................................................................. 8 DEBUGGING ............................................................................................................................................. 8 CODE COMPLEXITY.................................................................................................................................. 9 CODING PRACTICES ............................................................................................................................ 1 REFERENCES.......................................................................................................................................... 2
Introduction This document represents the coding standards established at GlobalSCAPE, Inc. Standardization of coding practices yields higher productivity through increased understanding, better organization, and higher re-use potential of source code. It is not the intent of coding standardization to inhibit programmer creativity; rather, coding is standardized only to the extent that the creativity and production of a programmer is done in an organized, logical, understandable, and repeatable manner. In short, any software developed at GlobalSCAPE, Inc. should be • Correct • Easy to Maintain In order to achieve these goals, the source that produces the software should: • Have a consistent style, • Be easy to read and understand, • Be free of common type errors, • Be maintainable by different programmers, • (Be portable on other architectures) Refer to the section entitled References at the end of this document for a collection of excellent material discussing guidelines for programming in C / C++. This document is based heavily on the coding standards recommended by the Ellemtel-rules found in the references. Source Files
Structure and Naming Conventions Rule 1
Include files always have the file name extension “.h”
Rule 2
Implementation files always have the file name extension “.cpp”
The purpose of these conventions is to provide a uniform interpretation of file names. There are two kinds of files generally accepted by C++ compilers: those which contain code that is accepted by both ANSI-C and C++ compilers and those which contain code that is only accepted by C++ compilers. It is appropriate to distinguish between the two in order to avoid misunderstanding as well as unpleasant compilation errors.
Exceptions Implementation files which contain code that is written specifically to ANSI C standards should have the file name extension “.c” to Rule 2:
File Naming Rule 3
Always give a file name that is descriptive and unique for the entire project. Use the same capitalization techniques used in source code for file names.
Comments It is imperative for understanding source code that it be well documented. Proper choice of variable names, method names, class names, etc. provides for self documenting code and reduces the need for comments within the code.
File Comments File comments are placed at the beginning of each source file in order to describe, in a high level fashion, the purpose of the file as well as to track any modifications / revisions made to the file.
Rule 4
Every file that contains source code must be documented with an introductory comment block that provides information on the contents, purpose, creation date, etc. See below for comment template and example.
Rule 5
All files must include copyright information
Rule 6
All comments are to be written in English
Rule 7
All documentation comments described in this section are to use the // comment marker. /* */ comment markers are reserved for testing and debugging. In other words, documentation in the form of comments shall always use the // markers; the /* */ markers shall be used exclusively for disabling code fragments during development.
The format for a file header comment is shown below. // // // // // // // // // // // // // // // // // // //
File: File Name here Description: descibe role or purpose of this file Created: date of file creation Author: Your_Name(s) with assistance from: Creation Date: Creation_Date modified: Modification_Date
reason
(one for each modification)
Copyright (c) 2000 GlobalSCAPE, Inc. The copyright to the computer program(s) herein is the property of GlobalSCAPE, Inc. The program(s) may be used and/or copied only with the written permission of GlobalSCAPE, Inc. or in accordance with the terms and conditions stipulated in the agreement/contract under which the program(s) have been supplied.
Example 1: File Header comment // // // // // // // // // // // // // // //
File: Description: Author: Created:
foo.cpp This is a test program that foos really well Gregory T. Hoffer 09 June 2000
Copyright (c) 2000 GlobalSCAPE, Inc. The copyright to the computer program(s) herein is the property of GlobalSCAPE, Inc. The program(s) may be used and/or copied only with the written permission of GlobalSCAPE, Inc. or in accordance with the terms and conditions stipulated in the agreement/contract under which the program(s) have been supplied.
Class, Method, and Function Comments Source code comments are often said to be either “tactical” or “strategic”. A strategic comment describes what a function or section of code is intended to do, and is placed before this code. A tactical comment describes what a single line of code is intended to do, and is placed, if possible, at the end of this line. Unfortunately, too many tactical comments can make code unreadable. For this reason, it is recommended to primarily use strategic comments, unless trying to explain very complicated code. The standardization of comments makes it possible to automatically generate external documentation (help files, man pages, etc.) from source code. This may be used to keep source code and documentation together until adequate tools for information management are available If the characters // are consistently used for writing comments, then the combination /* */ may be used to make comments out of entire sections of code during the development and debugging phases. C++, however, does not allow comments to be nested using /* */
Rule 8
Every Class declaration must be documented with an introductory comment block. See below for template and example.
Rule 9
Every Method and free function definition must be documented with an introductory comment block. See below for template and example.
Rule 10
Every block of code that is highly complex or particularly difficult to understand must be preceded with inline comments that describe the purpose and mechanism of that code.
Note: The Visual C++ Intellisense feature provides an option to display comments that are included with a function (refer to http://msdn.microsoft.com/library/devprods/vs6/visualc/vcug/vchowviewingcodecomments.htm). It is recommended that any function that requires special handling have comments added at the end of the declaration of that method.
The format for a class header comment is shown below. // CLASS DECLARATION // NAME: the name of this class // AUTHOR: author’s name // CREATED: creation date // MODIFIED: any modifications include date and mod notes here // PURPOSE: brief description of the purpose of this class // LIMITATIONS: any known limitations for this class // TESTING NOTES: name and descriptions of any test stubs, drivers, conditionals // defines, etc. that can be used to test this class // REUSE NOTES: note any potential reuse for this class, including any mods that // might have to be made to generalize the functionality
Example 2: Class Declaration comment // CLASS DECLARATION // NAME: CFooBar // AUTHOR: Gregory T. Hoffer // CREATED: 09 June 2000 // PURPOSE: this class acts as the controller for a CBar object, using the // Model/View/Controller design patter. The CBar is the model, CFoo // is the view // LIMITATIONS: tightly coupled with CBar and CFoo; consider revising // TESTING NOTES: be sure to test dynamic creation of CFooBar in multithreaded app // REUSE NOTES: this could serve as the basis for a specialized M/V/C component //
The format for a method or free function definition is given below // SUMMARY [CL x] where x is confidence level, 0-100%, of this method/function // NAME: the name of this function/method // AUTHOR: author’s name // PARAMS: include parameters and their purpose // RETURNS: type and purpose of return value from function // CREATED: creation date // MODIFIED: any modifications include date and mod notes here // PURPOSE: brief description of the purpose of this class // NOTES: general notes on the function/method // CODE WALKTHROUGH: Individual initials and date of person doing initial code // walkthrough (see quality factors section below) // UNIT TESTED: individual initials and date of person doing unit testing
Example 3: Method/Function definition comment // SUMMARY [CL 25] // NAME: CFooBar::doSomething // AUTHOR: Greg Hoffer // PARAMS: int iObjectID -- the id of currently selected item in model // struct action_type atAction -- what action to perform on object // RETURNS: boolean -- TRUE if successful, FALSE otherwise // CREATED: 09 June 2000 // PURPOSE: perform the requested action on the item currently selected in CBar // NOTES: // CODE WALKTHROUGH: 09 June 2000 RWE // UNIT TESTED: // don’t use this in Win95/98!!! [ this will show up in intellisense ] boolean CFooBar::doSomething( int iObjectID, struct action_type atAction ) { . . . }
Example 4 Strategic and Tactical Comments // THE NEXT TWO LINES ARE STRATEGIC COMMENTS // This function does some complicated things. It works like this: // blah-blah-blah ... int InsanelyGreatAndComplicatedFunction( int i ) { int Index = i++ + ++i * i-- - --i; // THIS IS A TACTICAL COMMENT return Index; }
Include Files
Rule 11
Every Include file must contain a mechanism to prevent multiple inclusions of that file. When any of the following kinds of definitions are used (in implementation or other include files), they must be included as separate include files:
Rule 12
Rule 13
• • •
classes that are used as base classes classes that are used as member variables classes that appear as return types or as argument types in function/member function prototypes • function prototypes for functions/member functions used in inline member functions that are defined in the file
Never specify relative pathnames in #include directives
The easiest way to avoid multiple includes of files is by using an #ifndef/#define block in the beginning of the file and an #endif at the end of the file True portable code is independent of the underlying operating system. For this reason, relative search paths should be avoided when including files. The processing of such search paths depends on the compiler and platform. Instead, search paths should be provided in `make' files as options for the compiler (which is equivalent to including them in the project workspace settings in Visual C++).
Inner classes can be used to declare classes that are member variables of another class ONLY under highly specialized situations in which industry Exceptions accepted and proven practices warrant their use. Due to potential reduced to Rule 12: reusability and possible misunderstanding of purpose, this practice should be avoided in the majority of situations. Examples of situations that might warrant inner classes would be iterators and aggregating com interfaces to implement inner and outer objects. Every C++ course teaches the difference between the include directives for user-prepared and for library include files. If the file name is bracketed between "<" and ">", the preprocessor will not search for the file in the default directory. This reduces the risk of unintended name collisions between user-prepared and library include files.
Assigning Names
Rule 14
The identifier of every globally visible class, enumeration type, type definition, function, constant, and variable in a class library is to be placed in a namespace that corresponds to that class library.
Rule 15
The names of variables, constants, and functions are to begin with a capital letter.
Rule 16
The names of abstract data types, structures, typedefs, and enumerated types are to begin with an uppercase letter.
Rule 17
In names which consist of more than one word, the words are written together and each word that follows the first is begun with an uppercase letter.
Rule 18
Do not use identifiers which begin with one or two underscores (`_' or `__').
Rule 19
Do not use type names that differ only by the use of uppercase and lowercase letters.
It is recommended identifiers not be extremely long, to reduce the risk for name collisions when using tools that truncate long identifiers. At the same time, identifiers should be expressive enough to convey meaning without requiring too much effort in language deciphering (for example, avoid abbreviations. This is especially important when dealing with developers of different national origins with different native languages). The use of two underscores (`__') in identifiers is reserved for the compiler's internal use according to the ANSI-C standard. Underscores (`_') are often used in names of library functions (such as " _main" and "_exit"). In order to avoid collisions, do not begin an identifier with an underscore. Recommendation: Industry Standard naming conventions, such as the well-established Hungarian Notation, provide an excellent set of conventions that conform to the above rules. It is recommended that such naming conventions be used as the basis for development while, at the same time, flexibility beyond such conventions (while still adhering to the above rules) be allowed. Recall that the ultimate goal of the above rules (#14-#19) is to provide for a consistent mechanism by which identifiers are mnemonic in characterizing their type and purpose. See the section below entitled Coding Practices for further details.
Style
Classes Rule 20
Rule 21
The public, protected, and private sections of a class are to be declared in that order (the public section is declared before the protected section which is declared before the private section). No member functions are to be defined within the class definition except for accessor methods (the “get” and “set” functions that manipulate nonpublic member variables)
By placing the public section first, everything that is of interest to a user is gathered in the beginning of the class definition. The protected section may be of interest to designers when considering inheriting from the class. The private section contains details that should have the least general interest. A member function that is defined within a class definition automatically becomes inline. Class definitions are less compact and more difficult to read when they include definitions of member functions. It is easier for an inline member function to become an ordinary member function if the definition of the inline function is placed outside of the class definition. Example 5 A class definition in accordance with the style rules class MyString : private Object { public: MyString(); // Default constructor MyString( const MyString& s ); // Copy constructor unsigned Length() const; unsigned GetNoOfChars() { return m_NoOfChars; }; unsigned SetNoOfChars(unsigned N) { return (m_NoOfChars = N); }; // ... protected: int CheckIndex( unsigned index ) const; // ... private: unsigned m_NoOfChars; // ... };
Functions
Rule 22
When declaring functions, the leading parenthesis and the first argument (if any) are to be written on the same line as the function name. If space permits, other arguments and the closing parenthesis may also be written on the same line as the function name. Otherwise, each additional argument is to be written on a separate line (with the closing parenthesis directly after the last argument).
Example 18 Right and wrong ways of declaring formal arguments for a function (in function definition) // Right: int MyComplicatedFunction( unsigned UnsignedValue, int IntValue, char* CharPointerValue, int* IntPointerValue, myClass* MyClassPointerValue, unsigned* UnsignedPointerValue ); // Wrong: int MyComplicatedFunction( unsigned UnsignedValue, int IntValue, char* CharPointerValue, int* IntPointerValue, myClass* MyClassPointerValue, unsigned* UnsignedPointerValue );
Compound Statements Rule 24
Braces ("{}") which enclose a block are to be placed in the same column, on separate lines directly before and after the block
“The placement of braces seems to have been the subject of the greatest debate concerning the appearance of both C and C++ code. We recommend the style which, in our opinion, gives the most readable code. Other styles may well provide more compact code.” [Ellemtel]
Flow Control Structures Rule 25
The code following a case label must always be terminated by a break statement
Rule 26
A switch statement must always contain a default branch which handles unexpected cases
Rule 27
Never use goto
Quality Factors The following rules are designed to ensure the highest level of quality in all software development. Quality derives from rigorous enforcement of sound design and coding principles as well as intelligent design of software that is easily tested and debugged.
Debugging Rule 28
Functions that make assumptions about variables or member data will validate those assumptions with an ASSERT macro.
Rule 29
Every non-trivial function shall include a TRACE macro denoting the entry point to that function. In addition, complex portions of code shall include the TRACE macro in order to track the flow of the function and program.
Rule 30
Every function shall include, at the beginning of the function definition, code that will log pertinent information. This code shall be delimited by preprocessor conditionals so that various compilations do not necessarily include all such logging. All exception and error handling shall always include logging regardless of compilation status (e.g., release versus Beta).
Rule 31
Do not use the preprocessor directive #define to obtain more efficient code; instead, use templated and/or inline functions.
Rule 32
Constants are to be defined using const or enum; never using #define nor arbitrary literals.
Liberal use of the ASSERT macro imposes no burden on a release build yet provides a robust mechanism for debugging an application during development and testing. Likewise, the TRACE macro provides useful information during initial development but is not included in release builds. Both mechanism above require only slight additional code / effort on the developer’s part while yielding significant gains in the testing and debugging of code. Inline functions have the advantage of often being faster to execute than ordinary functions. The disadvantage in their use is that the implementation becomes more exposed, since the definition of an inline function must be placed in an include file for the class, while the definition of an ordinary function may be placed in its own separate file. All constants shall be named rather than arbitrary literal values. This allows both for greater understanding as well as easier maintenance (through centralized definitions). The preprocessor performs a textual substitution for macros in the source code that is then compiled. This has a number of negative consequences. For example, if a constant has been defined using #define, the name of the constant is not recognized in many debuggers. If the constant is represented by an expression, this expression may be evaluated differently for different instantiations, depending on the scope of the name. In addition, macros are, at times, incorrectly written.
Code Complexity Rule 32
Code shall be written to accomplish, at most, a single logically distinct function per line.
Rule 33
No more than three levels of nested logic shall be used within a single function. Additional functions shall be used instead, when required.
Rule 34
No more than 9 control flow keywords (e.g., if, else, while, switch) shall be used in a single function. Additional functions shall be used instead, when required.
The complexity of an algorithm need not be accompanied by difficult to understand source code. Source code maintenance and future usability demands that source code be easy to understand; to that end, the complexity of source code shall be minimized by the above rules.
Coding Practices The following is a collection of recommended coding practices. These items fall outside the scope of formalized standards, yet are considerations that should be taken into account when attempting to write “good” code at GlobalSCAPE, Inc.
Practice 1
ASSERT macros shall be used to check assumed condition. VERIFY macros shall be used when checks carry out code that must execute in release mode.
Practice 2
Exception Handling shall be used in all projects to provide high levels of confidence in the ability of applications to gracefully recover from any unexpected (or expected!) error conditions. Graceful handling of exception conditions is highly preferable to GPFs, failed assertions, or simply unhandled (NOPs) exceptions.
Practice 3
All applications shall have a global exception handler that catches any exceptions thrown as a result of, but are not caught by the application. A typical method of accomplishing this would be to create a main function that wraps the instantiation of the application object in an exception handling block; or to warp the WinMain message loop in an exception handler.
Practice 4
Algorithms shall be coded to the standard case with exception handling used to catch any error conditions. Common sense shall dictate the tradeoffs in exception handling versus conditional execution.
Practice 5
Periodic peer reviews of software shall be done in order to ensure code quality. These peer reviews are used to solicit ideas, comments, suggestions, etc. on the various areas that lead to correct and maintainable code, including (but not limited to): Adherence to Coding Standards and Naming Conventions Sound logic Good Design, esp. Object Oriented Appropriate Syntax and Semantics Readability and Understanding, including comments
Practice 6
Program Managers shall “sign-off” on any code as the last step to delivering it. This results in the PM having accountability for the responsibility of deliverables meeting the requirement needs. It is recommended that PMs provide a second walk-through of code prior to delivering so that they are confident in the correctness of the deliverable meeting the established “contract” of the associated requirement.
REFERENCES Ellemtel Rules and Recommendations for Programming in C++
http://www.cs.umd.edu/users/cml/cstyle/Ellemtel-rules.html
GNU C coding standards
http://www.gnu.org/prep/standards.html
Indian Hill C Style and Coding Standards, updated
http://www.apocalypse.org/pub/u/paul/docs/cstyle/cstyle.htm
C++ Coding Standard
http://www.possibility.com/Cpp/CppCodingStandard.html
Charles Simonyi “Hungarian Notation”
http://msdn.microsoft.com/library/techart/hunganotat.htm