Home     Serna Editor     Products     Downloads     Partners     About    
Syntext C++ Coding Conventions

Syntext C++ Coding Style 2.0

Permission is granted to any institution or individual to use, copy, modify, and distribute this document, provided that this complete copyright and permission notice is maintained intact in all copies.

Syntext, Inc. makes no representations about the suitability of this document or the examples described herein for any purpose. It is provided “ as is ” without warranty of any kind.

E-mail suggestions to: info-general@syntext.com


Chapter�1.�C++ Programming Style

This document is mostly based on the papers listed in the bibliography. They prescribe conceptual rules some of which may be settled differently (e.g, variable naming conventions). These papers also prescribe detailed explanations for the rule settlements.

This paper prescribes the concrete rules for Syntext project development.

In development it is necessary to follow coding conventions for the following reasons:

  • It is necessary to avoid the typical coding mistakes

  • It is necessary to unify the view of different code fragments

  • In any code fragment any project programmer has to understand semantics rapidly

  • New people can get up to speed quickly

  • In some typical situations it is convenient to apply a worked out coding style for performance increase (both human and computer).

Because of the above-mentioned reasons source code ought to satisfy the following:

  • Should be consistent (has complete structure)

  • Should be clear for reading and comprehension

  • Should be portable

  • Must not contain typical mistakes

  • Available to any programmer for modification

  • Must not lead to performance loss.

The following definitions are used in the paper:

Rule - statement that must be strictly obeyed.

Recommendation - statement that should be followed if it does not lead away from prescribed goals and does not contradict the common sense.

Common Conventions

  1. Rule.� If a rule is broken it has to be explicitly documented.

  2. Recommendation.� Code is optimized only in the case of special performance requirements. Code is optimized only in extreme cases.

  3. Rule.� Code must never be copy/pasted (literally doubled). If two functionalities have the common parts, they must reuse single code portion.

File Organization

Common Conventions

  1. Rule.� Header files have .h extension.

  2. Rule.� Implementation files have .cxx extensions.

  3. Rule.� Automatically generated files have .hpp and .cpp extensions correspondingly.

  4. Recommendation.� Each header-implementation couple should contain not more than one class definition/implementation.

  5. Rule.� Header and implementation classes have to be named as the contained class+extension (case-sensitive). If class implementation is too large it may be split to files named like: ClassName_section.cxx

  6. Rule.� If files contains a collection of entities (classes, functions, variables, macro), then the file is named with lowercase letters divided with underscores, e.g. gui_geometry_structs.h(.cxx) .

Header Files

  1. Rule.� Each header file must prevent second inclusion. (See Example�1.1, “Second inclusion prevention” ). Macro names are to follow the pattern: MY_NAMESPACE_MY_CLASS_H.

  2. Rule.� #include < > directives must not include relative paths like '../' .

Example�1.1.�Second inclusion prevention

// This file contains the implementation of
// MyClass. Hence the file name is MyClass.h
// Multiple inclusion preventing macros is therefore:
 
#ifndef MY_NAMESPACE_MY_CLASS_H
#define MY_NAMESPACE_MY_CLASS_H
namespace MyNamespace {
class MyClass {
...
};
}
#endif // MY_NAMESPACE_MY_CLASS_H

Comments

Documentation implies literate programming . That is documentation to classes, functions, etc. is provided in the code, in special comments that are exported to documentation.

There are the two types of code comments:

  • Documenting comments .� Those forming the project documentation, i.e. describe given programming component, ways to use it, and the interfaces.

  • Explaining comments .� Those serving better (implementation) code comprehension.

Documenting comments have special form that allows documenting system to extract documentation. The concrete form is defined by chosen documentation system.

Note

At the moment of Coding Convention writing Syntext, Inc. uses Doxygen documentation system.

Explaining comments that use special keywords are called key comments (see Example�1.3, “Documented fragment sample ” ). They provide additional semantics in tagging specific code peculiarities. Non-key comments have arbitrary form.

Common Conventions

  1. Rule.� All comments are written in English.

  2. Recommendation.� Use "//" for explaining comments.

Explaining Comments

  1. Rule.� Keywords in key comments are separated with colon from the other words that are placed on the same line (see Example�1.3, “Documented fragment sample ” ).

  2. Recommendation.� Key comments are added if they do not cumber the code and increase visual presentation. (For example, if a class contains a constructor and a couple of functions there is no need in key comments).

  3. Rule.� Each code file must have a comment header, presented in Example�1.2, “File header” .

  4. Rule.� It is necessary to distinctly document code with the key comments where special attention needed in the following form: // KEYWORD: author date : comment text , where date is composed in YYMMDD form, for example 990619 (author and date are optional). Several line comments are acceptable, but the first string has to contain the principal statement. (See. Example�1.3, “Documented fragment sample ” ). The following keywords are accepted:

    • TODO.� Incomplete piece. Comments about what is to be done.

    • KLUDGE.� Dirty hack. Comments have to contain reasons for the workaround.

    • TRICKY.� Code is tricky and must not be modified without special attention.

    • WARNING.� Self-explanatory.

Example�1.2.�File header

// (c) 1998 by Syntext, Inc.
//
// This is a copyrighted commercial software.
// Please see COPYRIGHT file for details.
#ifndef XX_H
#define XX_H

Example�1.3.�Documented fragment sample

// TODO: ilia 960810 : performance problem. 
// We actually should use a
// hash table here, but for now we use a linear search.

Names

Common Conventions

  1. Rule.� All names are composed from English words and common English abbreviations.

  2. Rule.� Names must not begin with underscore "_".

  3. Rule.� Only team-accepted abbreviations may be used in the names, or the abbreviation must be immediately documented.

  4. Recommendation.� Name must distinctly describe an entity meaning.

    Note

    Name that is pronounced with difficulty is a bad name. If it is difficult to make up a name for an entity then possibly design has to be revised.

  5. Rule.� If a name contains an abbreviation then abbreviation is written with lowercase letters, leaving only first letter in uppercase. (See Example�1.4, “Only first letter of abbreviation is in uppercase. ” ).

  6. Rule.� Names of global identifiers must contain only uppercase letters, and containing words are to be separated with underscore "_".

  7. Rule.� Namespaces are named as classes (See the section called “Class, Enums and Typedefs Names” ).

  8. Rule.� Because method or function is an action, its name must contain a verb (See Example�1.5, “Function name example” ). Exceptions are the data member accessors.

  9. Rule.� Accepted prefix and suffix must be used. Among them:

    • Prefixes:

      • is.� - predicate (E.g. isSortable() ).

      • make.� - object-factory function/member

Example�1.4.�Only first letter of abbreviation is in uppercase.

class DssslScript;     // Not DSSSLScript
class SgmlEntity;      // Not SGMLEntity

Example�1.5.�Function name example

int Object::checkForErrors();  // Not errorCheck() !
int Object::dumpDataToFile();  // Not dataFile() !

Class, Enums and Typedefs Names

  1. Rule.� Names of classes, typedefs, enums and structs must begin with uppercase letter. Names consisting from more than one word are composed as uppercase letter separated words in lowercase.

  2. Recommendation.� If a class name consists of more than three words then the class design should be reviewed.

Class Component Names

  1. Rule.� Names of class methods and data members obey the same naming rules as for classes, except that they start from lowercase letter.

  2. Rule.� Private and protected data member names must end with underscore "_" (See Example�1.6, “Example of class member names” ).

Example�1.6.�Example of class member names

class Person {
public:
    enum Gender { MALE, FEMALE };
    Person( Gender gender, char* name) 
        : gender_( gender ), name_( name ) {}
    const        char* name() const;
    Gender       gender() const;
private:
    Gender       gender_;
    char*        name_;
};

Variable and Function Names

  1. Rule.� Formal parameter names must begin with lowercase letters, and then class name rules apply. (See Example�1.6, “Example of class member names” )

  2. Rule.� Automatic variable names must contain lowercase letters with underscore separated words "_". (See Example�1.15, “Switch-statement example” ).

  3. Rule.� Standalone functions must contain only lowercase letters with underscore separated words “ _ ”.

Names for Enum Items

  1. Rule.� Enum item names must contain uppercase letters with underscore separated words "_".

  2. Recommendation.� If enum is declared outside of a class, then items must have specific prefix.

  3. Recommendation.� In many cases it is recommended to add an “ invalid state ” item into an enum.

Style

Common Conventions

  1. Rule.� A line must not exceed 79 symbols.

  2. Rule.� Braces “ {} ” are disposed in the same column on a separate line if they correspond namespace, block or function. If braces correspond to class and keywords ( if , else , while , for , do ) then leading brace is placed on the same line as the keyword, separated by a whitespace. (See Example�1.7, “Brace positions “ {} ”” ).

  3. Rule.� Four-space indentation is used. Tabulation must not be used for indentation.

  4. Rule.� Definition blocks must be indented. (See Example�1.8, “Definition blocks” ).

  5. Recommendation.� If nesting exceeds 4 or 5 levels then it is recommended to review the code.

  6. Rule.� Whitespace must separate parenthesis and keywords (e.g if , else , while , for , do ).

  7. Rule.� Binary operators and operands are separated with whitespace.

Classes

  1. Recommendation.� Class members should be declared in the following order: public, protected, private .

  2. Recommendation.� Public constructors and destructors should be declared before the member functions.

  3. Rule.� Use classes, and not structs.

Example�1.7.�Brace positions “ {}

char* Object::fooBar()
{
    while (true) {
        // ... something
    }
}

Example�1.8.�Definition blocks

DWord       dword_;
DWord*      pDword_;
char        name_;      

Functions

  1. Rule.� Function definition/declaration must explicitly define return value type.

  2. Rule.� Function definition/declaration must be given in the following form: return value type, function name, leading parenthesis and the first argument should be placed on one line. If there is enough room then all the other arguments and closing parenthesis may also be written on the same line as the function name. Otherwise each additional argument must be written on a separate line (with the closing parenthesis directly after the last argument). (See Example�1.9, “Function declaration example” ).

  3. Rule.� Always write the left parenthesis after a function name. (See Example�1.9, “Function declaration example” ).

Example�1.9.�Function declaration example

int doComplexThing(int        intValue,
                   char*      charPointerValue,
                   int*       intPointerValue); 

Coding rules

Classes

Common Conventions

  1. Recommendation.� Class data members are at least protected , preferably private .

  2. Rule.� Member function implementation must not be given in the class declaration. Trivial functions that do not increase dependencies of the header (do not require additional #include "...." ) may have implementation in class declaration header.

  3. Rule.� Member functions which do not change object state must be declared as const .

  4. Recommendation.� Class that uses new for object allocation should declare copy constructor and assignment operator. Classes which semantics does not imply copying should declare private copy constructor.

  5. Rule.� All the base classes that have virtual functions must have virtual destructor.

  6. Recommendation.� In the derived classes virtual key word should be used for the reimplemented virtual functions.

  7. Rule.� If a class has one of the following functions: copy constructor, assignment operator, default constructor, then it must have all of the mentioned functions.

  8. Rule.� Assignment operator must not change object if it is assigned to itself.

  9. Rule.� Exceptions must not be used in destructors.

  10. Recommendation.� Assignment operator must return const reference.

  11. Recommendation.� Operator redefinition must be done with care and not change semantics.

  12. Recommendation.� Public member functions should not return non-const reference and pointers for data class members.

  13. Rule.� Class members that are initialized in constructor should be initialized as in the example Example�1.10, “Member date initialization ” .

Example�1.10.�Member date initialization

Person::Person(Gender gender, char* name) 
       : gender_(gender), name_(name) {}
// The following constructor has worse performance in comparison 
// to the previous one.
Person::Person(Gender gender, char* name) 
{
    gender_ = gender;
    name_  = name;
}
 

Functions

Note

If not otherwise mentioned the rules and recommendations are also applied to member functions.

  1. Recommendation.� Functions with the large number of arguments should be avoided.

  2. Recommendation.� It is necessary to avoid large and complicated functions (more than 50-60 lines).

    Note

    If function is large, then its comprehension is complicated.

    Bugs are localized easier in short functions.

  3. Rule.� Function arguments must be passed as const references and not by value.

  4. Rule.� Formal parameter names must be specified in declarations and coincide with the names in definitions.

  5. Rule.� Not any function must return a reference or a pointer to its local variable.

  6. Rule.� Macros must not be used in the situation when inline-function may be used.

Constants

  1. Rule.� Constants must be defined with const or enum and never with #define .

    Note

    This makes debugging easier

  2. Rule.� Numerical values (except marginal like 0 or 1) must not be used in the code, but defined with constants or enums.

Variables

  1. Rule.� Each variable must be declared in a separate statement. (See Example�1.11, “Variable declaration ” ).

  2. Recommendation.� Variables must be declared in minimal scope. This recommendation may be neglected in specific cases of optimization (like cycle optimization).

  3. Rule.� Always initialize variables in the declaration or by their first usage. Always. Every time.

  4. Rule.� When possible initialization, but not assignment must be used (See Example�1.12, “Assignment in initialization ” ).

  5. Rule.� Unsigned must be always be used for variables that semantically may not have negative values.

Example�1.11.�Variable declaration

char* i; // Correct 
char  j; // declaration
char* i, j; // Error prone!!!
 

Example�1.12.�Assignment in initialization

void fooBar(complex const& z)
{
    complex z1 = z;   
    complex z2;
    z2 = z;
    // Initialization of z1 has better performance than 
    // that of z2
}
      

Pointers and References

  1. Rule.� Qualifiers " * " and " & " in declaration/definitions must not be separated from type names.

  2. Rule.� NULL macro must not be used. It is necessary to use 0 instead.

  3. Rule.� When using pointers to functions typedef must be used (for syntax simplification).

Expressions and Statements

  1. Rule.� Empty cycle body must always be commented and placed on a separate line. (See Example�1.13, “Empty cycle body” ).

  2. Rule.� Constants are placed on the left side of "==" expressions. (E.g. if (6 == errorNum) { )

  3. Rule.� Statements with simultaneous assignments must always be commented and taken in the additional parenthesis. (See Example�1.14, “Assignments in statements” ).

    Note

    Without such a comment a code may easily be "corrected" by another team member.

  4. Rule.� Code following case must always end with break if even if it is the last case in a switch . If a “ fall through ” is implied, it must be commented. (see Example�1.15, “Switch-statement example” ).

  5. Rule.� Switch must always have default (see Example�1.15, “Switch-statement example” ).

  6. Rule.� If local variables are used in switch then this part of code should be placed into a block. (See Example�1.15, “Switch-statement example” ).

  7. Rule.� Conditions in "? :" operator must be taken in parenthesis for the sake of readability; if the statements are long then they must be placed in separate lines. (See Example�1.16, “Operator "? :"” ).

  8. Rule.� One line must contain only one statement except for the cases when they are very close in meaning.

  9. Recommendation.� When in doubt of priorities parenthesis, must always be used.

Example�1.13.�Empty cycle body

while (*dest++ = *src++)
    ;     // VOID
      

Example�1.14.�Assignments in statements

if ((aBool = bBool)) {  // ASSIGNMENT
...                   
}                     
      

Example�1.15.�Switch-statement example

switch ( number_ ) {
    case 1:
        os << "Red";
        
        // FALL THROUGH
    case 2:
        {
             int tmp_var;
             ....
        }
        break;
    
    default:
        throw BadCondition();
        break;
}
      

Example�1.16.�Operator "? :"

(condition) ? func1() : func2();
or
(condition)
    ? long statement
    : another long statement;
      

Memory Allocation

  1. Rule.� Malloc , realloc , and free must not be used (except for specific low-level implementations).

  2. Recommendation.� There should be minimum of global identifiers.

  3. Recommendation.� Pointers to freed memory must always be assigned a value (in most cases 0).

  4. Rule.� Static objects with constructors are deprecated. Use singletons instead.

Portability

  1. Rule.� No assumption must be taken on physical representation of the fundamental types (and pointer), and their mutual correspondence.

  2. Rule.� char must not be assumed as signed or unsigned .

  3. Rule.� No assumptions must be taken on type specifics in overflow cases.

  4. Rule.� No assumptions on the order of member constructor execution must be taken. (See Example�1.17, “The order of object initialization may be undefined. ” ).

  5. Rule.� No assumption on the initialization order of static objects must be taken.

  6. Rule.� No assumption that function parameters are passed in any special order must be taken.

Example�1.17.�The order of object initialization may be undefined.

X::X(int y) : j(y), i(j)   // No! j may not be initialized before i !
{
    // Some code
}

Chapter�2.�Miscellaneous

General Principles of Interaction Within Developer Team.

  1. Rule: Do not duplicate what was done.� If some functionality is already implemented, it must be used. Creating alternatives is prohibited. If the interface or the implementation of the functionality does not satisfy a developer he should talk about the enhancements, and must not create yet another version.

  2. Rule: Ask others if it was done.� If a programmer suspects that the problem faced has already been implemented then he must ask the team on e-mail on available solution.

  3. Rule: Inform others on what was done.� Members must inform team on new reusable components implemented.

Essential Conditions for Code Development

Create early and not often:

  • Version control system (e.g. CVS)

  • Unified debugging system

  • Project tracking system

  • Bug-tracking system

  • Responsible build-master ( make environment, Makefile support).

  • Responsible for every module. Only the responsible may approve committing module modifications.

Bibliography

Ellemtel Telecommunication Systems Laboratories . Programming in C++, Rules and Recommendations (1993-12-31, Rev. C) . Available online.

Todd Hoff . C++ Coding Standard (October 31, 1997) . Available online.

Leo Michelotti . Light and Non-Controversial Coding Styles (February 14, 1997) . Available online.

Bjarne Stroustrup . The C++ Programming Language, 3rd Edition . Copyright � Addison-Wesley, 1997. 0-201-88954-4.