Thursday, May 09, 2013

Simple and Basic C++ Coding Conventions

1. Introduction



Most basic concept of C++ style rule is Use common sense and always be consistence inside the project. Most common logic of software development is that 10% of the cost of a project goes into writing code, while more than 50% is spent on maintaining it.
Think about the trade-offs between ease-of-programming now vs. ease-of-maintenance for the next 5 to 10 years when you consider the recommendations presented here.
The establishment of a common style will facilitate understanding and maintaining code developed by more than one programmer as well as making it easier for several people to cooperate in the development of the same program. The point of having style guidelines is to have a common vocabulary of coding so people can concentrate on what you are saying, rather than on how you are saying it. This document present global style rules here so people know the vocabulary. But local style is also important. If code you add to a file looks drastically different from the existing code around it, the discontinuity throws readers out of their rhythm when they go to read it. Try to avoid this. If you are editing code, take a few minutes to look at the code around you and determine its style.


2. Coding conventions


2.1. Files

  1. There should be one include class declare header file for each source code file.
  2. Each include file should describe a single class or tightly integrated set of classes.
  3. The name of the file should be the name of the class contained in the file without the leading "C". And file names should begin with lower case letters.
  4. File names should limited up to 30 characters.
  5. File names and directory paths should not contain blanks, parentheses "(", or crazy characters
  6. File header comments shall be placed at the top of each file stating the name of the file and comments on the file contents [Appendix 01].
  7. Do not use filenames that already exist in STL Fine names should be lowercase and words separate by underscore sign. 
  8. Each project should have a readme.txt file

2.1.1. Header Files(.hpp)

  1. Header files should only to contain definitions and NOT instantiations. Thus the include file can be used in multiple files.
  2. All header files should have #define guards to prevent multiple inclusions.
  3. The format of the symbol name should be FILENAME_H_
  4. Do not use #pragma once.
  5. If a class in a header file does not need to know the size of a data member class or does not need to use the class's members then forward declare the class instead of including the file.
  6. When including use standard order for readability and to avoid hidden dependencies: C library, C++ library, other libraries' .hpp, your project's .hpp.
  7. Within each section, includes should be ordered alphabetically.
  8. Do not include files with full path. Include statements should be documented, telling the user why a particular file was included.
  9. If the file includes a class used by the class then it's useful to specify a class relationship.
  10. C++ header files often use the suffix ".hpp" while "C" header files use ".h" suffix.
  11. Avoid the use of "namespace" in the ".hpp" include file.

2.1.2. Source file(.cpp)


  1. C++ source files should have a .cpp extension. Each source file should always have a header file with same name and a .hpp extension.
  2. The source file defines code and It instantiates definitions defined in the include file.

2.1. Namespace


  1. Unnamed namespaces in .cpp files are encouraged.
  2. Do not use a using-directive outside the classes in .hpp files.
  3. You may use a using-declaration anywhere in a .cpp file, and in functions, methods or classes in .hpp files.
  4. Do not use unnamed namespaces in .hpp files.
  5. Namespaces wrap the entire source file after includes, definitions/declarations, and forward declarations of classes from other namespaces.
  6. Do not use namespace aliases are outside of the named namespace in .hpp.
  7. Namespace names should be all lower-case.

2.2. Class and structures

  1. Be sure to add virtual to the base class destructors.
  2. Access modifier sequence should be public, protected then private and the declaration order should be
    • Typedefs and Enums 
    • Constants (static const data members)
    • Constructors 
    • Destructor 
    • Methods, including static methods
    • Data Members (except static const data members)
  3. Avoid doing complex initialization in constructors (in particular, initialization that can fail or that requires virtual method calls). 
  4. When redefining an inherited virtual function, explicitly declare it virtual in the declaration of the derived class
  5. If class doesn’t have other constructors you must define a default constructor (one that takes no arguments) and use to initialize the members.
  6. Use the keyword explicit for constructors with one argument except copy constructor.
  7. Do not overload operators except in rare, special circumstances

2.3. Functions

  1. Define functions inline only when they are small, say, 10 lines or less.
  2. Try to keep function short and simple (around 40 lines).
  3. When defining a function, parameter order is: inputs, then outputs.
  4. Write some descriptive comments before every function, telling the user what you did and why.
  5. Use completely global functions rarely and put nonmember functions in a namespace avoid polluting the global namespace.
  6. Place a function's variables in the narrowest scope possible, and initialize variables in the declaration.
  7. Function names should be descriptive; eschew unknown abbreviation, should be "command" verbs.
  8. Regular functions name should start with a capital letter and have a capital letter for each new word. No underscores.
  9. Accessors and mutators (get and set functions) should match the name of the variable they are getting and setting


2.4. Variables

  1. Variable names should be descriptive; eschew unknown abbreviation types and should be nouns.
  2. Name should be lowercase and use underscore to combine nouns (my_variable
  3. Class member variables have trailing underscores (my_variable_)
  4. Declare object variable used in a loop outside that loop.
  5. Variables are to be declared with the smallest possible scope.
  6. Avoid local variable definitions that override (hide) variables defined at higher levels.
  7. Try not to use Static or global variables of class type.
  8. Consider to use const in possible locations.
  9. Try not use variable length arrays, use vectors instead.
  10. Data members in structs should be named like regular variables without the trailing underscores that data members in classes have.
  11. Use prefix g_ with global variables. But discourage to use global variables.
  12. Use prefix c_ for constants variables.
  13. Do not use Hungarian notation
  14. A global variable would be instantiated in the ".cpp" file and NOT the ".hpp" file

2.5. Comments

  1. When writing your comments, write for your audience: the next contributor who will need to understand your code. Be generous.
  2. Start each file with license boilerplate, followed by a description of its contents with header comments.
  3. Do not duplicate comments in both the .hpp and the .cpp.
  4. Every class definition should have an accompanying comment that describes what it is for and how it should be used.
  5. Every function declaration should have comments immediately preceding it that describe what the function does and how to use it.
  6. What the inputs and outputs are should comment in function definition.
  7. If there ant special things to mention about the function, It should comment above the function definitions (How it does the job).
  8. Each class data member (also called an instance variable or member variable) and global variables should have a comment describing what it is used for.
  9. In your implementation you should have comments in tricky, non-obvious, interesting, or important parts of your code. But not everywhere.
  10. Note that you should never describe the code itself. Assume that the person reading the code knows C++.
  11. Use TODO comments with your email for code that is temporary, a short-term solution, or good-enough but not perfect. (TODO(kl@gmail.com): Need to implement thread safe.)


2.6. Formatting

2.6.1. Function declaration and definition

  1. Simple function
    ReturnType ClassName::FunctionName(Type par_1, Type par_2){
      DoSomething();
      ...
    }
  2. With long argument list.
    ReturnType LongClassName::ReallyReallyReallyLongFunctionName(
        Type par_1
        Type par_2,
        Type par_3){
      DoSomething();
      ...
    }
    
  3. The return type is always on the same line as the function name.
  4. The open parenthesis is always on the same line as the function name.
  5. There is never a space between the function name and the open parenthesis.
  6. There is never a space between the parentheses and the parameters.
  7. The open curly brace is always at the end of the same line as the last parameter.
  8. The close curly brace is either on the last line by itself or on the same line as the open curly brace.
  9. All parameters should be named, with identical names in the declaration and implementation.
  10. All parameters should be aligned if possible.
  11. If some parameters are unused, comment out the variable name in the function definition for future use.


2.6.2. Function call

  1. Simple function call
    bool retval = DoSomething(argument1, argument2, argument3);
  2. If the function has many arguments, consider having one per line if this makes the code more readable.
    bool retval = DoSomething(argument1,
                              argument2,
                              argument3,
                              argument4);
    

2.6.3. Conditionals

  1. Simple condition.
    if(condition){ 
      ... 
    }else if(...){ 
      ...
    }else{
      ...
    }
  2. Short conditional statements may be written on one line if this enhances readability.
    if (x == kFoo) return new Foo();
    if (x == kBar) return new Bar();
    

  3. Do not write short conditional statement when the “if” statement has an “else”.
    if (x == kFoo){
      return new Foo();
    }else{
      return new Bar();
    }
    

  4. When you have a Boolean expression that is longer than the standard line length, break up  to the lines.
    if (this_one_thing > this_other_thing &&
        a_third_thing == a_fourth_thing &&
        yet_another && last_one) {
        ...
    }

2.6.4. Loops and switch statements

  1. Simple switch always should have default and break.
    switch (var){
      case 0:
        ...
        break; 
      case 1:
        ...
        break; 
      default:
        assert(false); 
    }

  2. If the content of the cases are too long should use curly brackets.
    switch (var){
      case 0:{
        ...
        ...
        ...
        ...
        break;
      } 
      default: {
        assert(false);
      }
    }
    
  3. Simple while loop.
    while(condition){
      ...
    }
  4. Simple for loop.
    for(int i=0; i<10; ++i){
      ...
    }

  5. Empty body loops should use “continue” or “{}”, but not single semicolon.
    while(condition){} not while(condition);
    

2.6.5. Pointer and Reference Expressions

  1. When declaring a pointer variable or argument, you may place the asterisk adjacent to the variable name.
    char *a;
    const string &str;
    

2.6.6. Preprocessor Directives and Macros

  1. Preprocessor directives are within the body of indented code or begin of the file; the directives should start at the beginning of the line.
  2. Macro names should name with all uppercase and underscores.

2.6.7. Class

  1. Any base class name should be on the same line as the subclass name, subject to the 80-column limit.
    class MyClass : public OtherClass {
      ...
      ...
    };

  2. Type names (for classes, structs, typedefs, and enums) start with a capital letter and have a capital letter for each new word, with no underscores: MyExcitingClass.
  3. Constructor initializer lists can be all on one line or with subsequent lines if there are more things to initialize.
    MyClass::MyClass(int var) : var_(var), var2_(var + 1) {}
    
    
    MyClass::MyClass(int var)
    : var_(var),
      var2_(var + 1),
      var3_(var + 2)  {}

  4. The contents of namespaces are should not indented.

    namespace {
    void foo() {
      ...
      ...
    }
    }

2.6.8. Horizontal Whitespace

  1. Keep white spaces both sides of operator like =, +, -, / , && according to the place it uses.
    x = 0;
    x = -5;
    ++x;
    if (x && !y)
    v = w*x + y/z;
    v = w * (x + z);
    

  2. Keep space after each semicolon or colon exist before the line end.
    for ( ; i < 5 ; ++i)
    for (auto x : counts) {)
    

2.6.9. Vertical  Whitespace

  1. Do not waste new lines.
  2. Put one blank line between functions.
  3. Do not leave blank lines at the beginning or end of a function.

2.7. Other

  1. Use C++ casts like static_cast<>(). Do not use other cast formats like int y = (int)x; or int y = int(x);
  2. Use prefix form (++i) of the increment and decrements operators with iterators and other template objects.
  3. Use const whenever it makes sense and consider making data members const whenever they do not need to be modified after construction.
  4. Try not to use unsigned integers.
  5. Use 0 for integers, 0.0 for reals, NULL for pointers, and '\0' for chars when necessary.
  6. Use sizeof(variable) instead of sizeof(type) when you need to get the size of a variable.
  7. Each line of text in your code should be at most 80 characters long.
  8. Avoid the use of numeric values or hardcode values in code; use symbolic values instead.
  9. Do not allocate memory and expect that users will de-allocate it later.

3. Appendix -01

/*******************************************************************
File:  filename.ext
Author:  Author Name
E-Mail:  author@yourcompaney.com
Description:  Here is the area that should describe what is the usage of this class and what is the functionality of the class and the important things that need to mentions. 
Language:  C++
Version: 1.0
Limitations: none/some (i.e: limitations such as file size string lengths etc..)
Copyright: Your Companey
Thread Safe:  yes/no  
Extendable:  yes/no  
Platform Depend:none/some (i.e.: Linux/Intel, Windows/Intel, Solaris/SPARC)
Change History:
--------------------------------------------------------------------
Date   Author   Description
YYYY-MM-DD  Author Name  What is the improvement or change have done because of which reason
*******************************************************************/



Referance

  1. The C++ Programming Language,  By  Bjarne Stroustrup  
    Publication Date: June 30, 1997 | ISBN-10: 0201327554 | ISBN-13: 978-0201889543 | Edition: 3
  2. C++ Coding Standards: 101 Rules, Guidelines, and Best Practices,  By Herb Sutter  and Andrei Alexandrescu
    Publication Date: November 4, 2004 | ISBN-10: 0321113586 | ISBN-13: 978-0321113580 | Edition: 1
  3. http://cpp.capibara.com
  4. http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml
  5. http://www.yolinux.com/TUTORIALS/LinuxTutorialC++CodingStyle.html

3 comments:

  1. All excellent points and very important for all the aspiring bloggers to take a note.
    affordable web development company

    ReplyDelete
  2. Very good coding vonventions! I will add just to use nullptr, not NULL for pointers.

    ReplyDelete