0% found this document useful (0 votes)
6 views46 pages

Corporate Programming Standards C C++

The document outlines the Corporate Programming Standards for C/C++ at Wincor Nixdorf, providing guidelines to ensure high-quality, reliable, and maintainable software development. It covers various aspects including source code structure, naming conventions, design rules, formatting, documentation, and best practices. These standards are mandatory for all relevant departments within the organization and aim to promote consistency and adherence to industry standards.

Uploaded by

Ksontini Mejdi
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
6 views46 pages

Corporate Programming Standards C C++

The document outlines the Corporate Programming Standards for C/C++ at Wincor Nixdorf, providing guidelines to ensure high-quality, reliable, and maintainable software development. It covers various aspects including source code structure, naming conventions, design rules, formatting, documentation, and best practices. These standards are mandatory for all relevant departments within the organization and aim to promote consistency and adherence to industry standards.

Uploaded by

Ksontini Mejdi
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 46

Corporate Programming Standards - C/C++

Corporate Programming Standards -


C/C++

for Wincor Nixdorf

Document category: Architecture and Development Guidelines


Title: Corporate Programming Standards - C/C++
Document number: Policy 07/2010
Version 1.0
Approval status: Released
Editor/Author: WN Software Architecture Community
Responsible: Reinhard Rabenstein, CTO
Roger Zacharias, CTO-CAM
Creation date/update: July 2010
Protection class: PUBLIC

Version: 1.0 - public - Page: 1 / 1


Copyright © WINCOR NIXDORF, 2010
Corporate Programming Standards - C/C++

Table of Contents

1 Document..........................................................................................6
1.1 Distribution List ..................................................................................................6
1.2 Editors ................................................................................................................6
1.3 Status .................................................................................................................7
1.4 Document validity...............................................................................................7
1.5 History ................................................................................................................7
1.6 Reviews..............................................................................................................7
1.7 Copyrights ..........................................................................................................8
1.8 Document Confidentially ....................................................................................8

2 Overview ...........................................................................................9
2.1 Introduction ........................................................................................................9
2.2 Scope of this guidelines .....................................................................................9

3 Source Code Structure ..................................................................11


3.1 Class structure: one .cpp and one .h(pp).........................................................11
3.2 Header inclusion must be self-sufficient. .........................................................11
3.3 Inclusion order..................................................................................................11
3.4 Inclusion guards...............................................................................................12
3.5 Use namespaces for API classes ....................................................................12
3.6 Class length and responsibility ........................................................................13
3.7 Build without warnings .....................................................................................13

4 Names and declarations ................................................................14


4.1 Naming Convention .........................................................................................14
4.2 Declaration rules ..............................................................................................14
4.2.1 Declare as locally as possible .............................................................14
4.2.2 Sort variables by meaning ...................................................................14
4.2.3 Use meaningful names........................................................................14
4.2.4 One purpose only ................................................................................15
4.2.5 One declaration per line ......................................................................15
4.2.6 Don’t cover external declarations ........................................................15
4.2.7 Use declarations in for-loops only in the loop......................................15
4.2.8 For-Loop counter .................................................................................15
4.2.9 While-loop counter...............................................................................16
4.3 Initialization ......................................................................................................16
4.3.1 Initialize all variables............................................................................16
4.3.2 One initialization per line .....................................................................16

Version: 1.0 - public - Page: 2 / 2


Copyright © WINCOR NIXDORF, 2010
Corporate Programming Standards - C/C++

4.4 Class names are written in CamelCase...........................................................16


4.5 Function syntax rules .......................................................................................16
4.5.1 Prefixes for exported C functions ........................................................16
4.5.2 No prefixes for C++ functions ..............................................................17
4.5.3 Meaningful names ...............................................................................17
4.5.4 Function declaration ............................................................................17
4.6 #define syntax rules......................................................................................17
4.6.1 The name of a define has to be module specific.................................17
4.6.2 Redefinitions of macros are not permitted...........................................17
4.6.3 Macro names are written in UPPERCASE..........................................18

5 Design and programming rules ....................................................19


5.1 Avoid global variables ......................................................................................19
5.2 Prefer the stack over the heap.........................................................................19
5.3 Prefer new / delete........................................................................................19
5.4 Prefer references as method arguments .........................................................20
5.5 Use const for immutable values ...................................................................20
5.6 Use const for read-only member functions ......................................................21
5.7 Avoid Macros ...................................................................................................21
5.8 Prefer “const” variables or enumerators over #define .....................................21
5.9 Avoid compiler switches...................................................................................21
5.10 Prefer classes over structs...............................................................................22
5.11 Stay downward compatible ..............................................................................23
5.12 Hide as much data as possible ........................................................................23
5.13 Write virtual destructors for base classes ........................................................23
5.14 Method length ..................................................................................................24
5.15 Range checks on input data ............................................................................24
5.16 Avoid non-range-checking functions................................................................25
5.17 Return value validation ....................................................................................25
5.18 Use sizeof ........................................................................................................25
5.19 Avoid machine dependent fill methods ............................................................25
5.20 Don’t trust the byte order .................................................................................25
5.21 Pointer assignment ..........................................................................................26
5.22 Pointer validity..................................................................................................26
5.23 No sprintf on overlapping buffers:...............................................................26
5.24 new / delete and new[] / delete[] pairs must match...............................26
5.25 Do not use goto ..............................................................................................26
5.26 Avoid magic numbers ......................................................................................26

6 Formatting and notation rules ......................................................28


6.1 public / protected / private indention level ...........................................28
6.2 public / protected / private order ......................................................................28

Version: 1.0 - public - Page: 3 / 3


Copyright © WINCOR NIXDORF, 2010
Corporate Programming Standards - C/C++

6.3 class and namespace indention level...........................................................28


6.4 Conditions in a control structure ......................................................................28
6.5 Line length........................................................................................................29
6.6 Curved brackets ...............................................................................................29
6.7 Indent level.......................................................................................................29
6.8 Switch-case syntax ..........................................................................................29
6.8.1 Each switch has a break.................................................................29
6.8.2 Always provide a default .................................................................29
6.9 Break and continue ..........................................................................................30
6.10 Blank usage .....................................................................................................30
6.10.1 Use blanks around binary operators .................................................30
6.10.2 Use a blank after commas in argument lists or value lists ................30
6.10.3 Use a blank after semicolons if it does not delimit a code line..........30
6.10.4 Use a blank after control flow statements. ........................................30
6.11 Comment indention..........................................................................................30

7 Documentation and commenting..................................................31


7.1 General rule: why, not what .............................................................................31
7.2 No trivial comments .........................................................................................31
7.3 Out-commented code blocks ...........................................................................31
7.4 Class description in the header (Doxygen-like) ...............................................32
7.5 Method description in the header (Doxygen-like) ............................................32
7.6 Comment members of a class Doxygen-like ...................................................33
7.7 Beginning comments .......................................................................................33
7.8 Comment #includes in public interfaces ......................................................33

8 Guidelines for unit testing.............................................................34

9 Best Practices ................................................................................35


9.1 Distinguish between prefix and postfix forms of increment and decrement
operators when overloading operators ............................................................35
9.2 Define class type variables using direct initialization rather than copy
initialization.......................................................................................................35
9.3 The #define pre-processor directive shall not be used to create inline macros.
Inline functions shall be used instead. .............................................................35
9.4 Do not define a class template with potentially conflicting methods................36
9.5 Only instantiate templates with template arguments which fulfill the interface
requirements of the 'template'..........................................................................36
9.6 Use empty() instead of checking size() against zero.......................................36
9.7 Use Standard Template Library containers and algorithms in preference to
custom designs. ...............................................................................................37
9.8 Never modify the key part of a set or multiset element. ..................................37
9.9 Prefer composition over inheritance ................................................................37

Version: 1.0 - public - Page: 4 / 4


Copyright © WINCOR NIXDORF, 2010
Corporate Programming Standards - C/C++

9.10 Do not use implicit casting ...............................................................................38


9.11 Use explicit in single-parameter constructors............................................38
9.12 Be careful when using unsigned numbers in loops .........................................39

10 Check List for Source Reviews .....................................................40


10.1 Source Code Structure ....................................................................................40
10.2 Names and Declarations..................................................................................40
10.3 Design and programming rules........................................................................41
10.4 Formatting and notation rules ..........................................................................42
10.5 Documentation and commenting .....................................................................43

A 1 List of Tables ..................................................................................44

A 2 Referenced Documents .................................................................46

Version: 1.0 - public - Page: 5 / 5


Copyright © WINCOR NIXDORF, 2010
Corporate Programming Standards - C/C++

1 Document

1.1 Distribution List


Department Contact
BD SWD Dr. Christian Schlögel
RD SWD Nicolas Pelletier
RD LOT E Rainer Harasko
RD SSI E Andreas Kohlmann
WNT E Dr. Reiner Seitz
BD HWD Hans-Günter Voss
BD SW QA Hubert Segin
RD SW QA Heinrich Endeward
BD SW&PS Karl-Heinz Kern
BCON Jost-Jürgen Veit
RCON Achim Sieren
SD MS Andreas Vogt
CF CIO Kirsten Dorsch
CF CTO Reinhard Rabenstein
LE R&D departments
Table 1 Document Distribution List

1.2 Editors
Name Department E-Mail
Miran Miksic BD HWD 2 [email protected]

Eike Rethmeier BD SWD 3 [email protected]

Patrick Urban BD SWD 3 [email protected]

Nico vom Hagen BD SWD 5 [email protected]

Dr. Matthias Paul CF CIO 1 [email protected]

Markus Haack CF CTO [email protected]

Roger Zacharias CF CTO [email protected]

Bo Zhao CN ASP SSD-D [email protected]

Elmar Harder RD LOT E [email protected]

Rainer Kramer RD SSI [email protected]

Version: 1.0 - public - Page: 6 / 6


Copyright © WINCOR NIXDORF, 2010
Corporate Programming Standards - C/C++

Simon Boymann WNT E [email protected]

Table 2 Document Editors

1.3 Status
In progress

Review version

Review status

9 Released
Table 3 Document Status

1.4 Document validity


This document, in its current version, is valid immediately after the final approval, as long as
there is no newer version of this document.

1.5 History
When extending the history, don’t forget to write the current version number onto the front
page of this document.
Version Date Responsible Sections Changes
WN Software Archi-
1.0 27th July all Initial version
tecture Community

Table 4 Document History

1.6 Reviews
Version Date Responsible Sections Result
WN Software Archi-
1.0 27th July all Version 1.0 released
tecture Community

Table 5 Document Reviews

Version: 1.0 - public - Page: 7 / 7


Copyright © WINCOR NIXDORF, 2010
Corporate Programming Standards - C/C++

1.7 Copyrights
Almost all the hardware and software names that appear in this document are registered
trademarks of their respective product owners and should be treated as such. In its references
to product names, Wincor Nixdorf uses the version commonly adopted by the vendors.

1.8 Document Confidentially


© Wincor Nixdorf, 2010 - The contents of this document may not be reproduced, exploited or
published, wholly or in part, without the prior written permission of Wincor Nixdorf. This also
includes translations into other languages. The copyright applies to all forms of storage and
reproduction that contain the information in this document, including but not limited to mag-
netic memory, computer printouts and visual displays. Offenders are liable to payment of
damages. All rights, including rights created by patent grant or registration of a utility model or
design, are reserved.

Right of technical modifications reserved.

Version: 1.0 - public - Page: 8 / 8


Copyright © WINCOR NIXDORF, 2010
Corporate Programming Standards - C/C++

2 Overview

2.1 Introduction
This document describes a set of rules, guidelines and recommendations used when writing
the source code for C/C++ programs. It presents a set of specific guidelines for using the fea-
tures of C/C++ in a disciplined manner.
The goal of each developer should be to develop high quality, reliable, reusable, portable
software. For a number of reasons, no programming language can ensure the achievements
of these desirable objectives on its own. Programming must be embedded in a disciplined de-
velopment process that addresses a number of topics in a well managed way.
These guidelines ensure these goals by supporting the developer to program in an easy to
read and easy to maintain, reusable and portable way. By complying with these guidelines it
makes it easier for other developers to read and maintain the source code, because every
code has a consistent “layout”.
These guidelines contain as well syntactical rules, which may be checked by any static code
checker (like being consistent with the indent level), as well as semantic rules. Semantic rules
are harder to check, because in normal cases they require a code review by another software
developer. Both, establishing static code analysis tools and setting up code reviews, are part
the Early QA process.
In general it is required to follow all guidelines listed below. Nevertheless in some special cas-
es it may be even advisable to disregard certain guidelines, e.g. if technical reasons suggest
otherwise.
Wincor Nixdorf is committed to follow open and industry standards. This also applies to Cod-
ing and Code Style rules for our software development departments; therefore, this document
is based on conventions and guidelines from different organizations and well-known authors.
References to external sources are marked as such and may be taking into account when ap-
plying these rules or when looking for further examples of a good coding style.
Many of these rules are not applicable to pure C (in contrast to C++) programs. In such a case
just apply all rules which are usable for C.

2.2 Scope of this guidelines


These corporate programming standards:
• take effect immediately
• are mandatory for:
• all Wincor Nixdorf R&D departments worldwide
• all Wincor Nixdorf Legal Entity development departments
• all Wincor Nixdorf Professional Services departments worldwide
• all Wincor Nixdorf Service Division departments worldwide
• all Wincor Nixdorf internal departments (like CIO, CTO, HR, etc.) worldwide
• all Wincor Nixdorf sub companies and organizations (like WNT, BCon, RCon, etc.)
worldwide

Version: 1.0 - public - Page: 9 / 9


Copyright © WINCOR NIXDORF, 2010
Corporate Programming Standards - C/C++

• all contracted or commissioned external staff, sub contractors or partners


• and have to be applied to:
• every new software component (e.g. new functionality block for a new or existing ap-
plication)
• every significantly changed software component (i.e. more than 30% content changes
within the component between two component versions)
• every new software application

These corporate programming standards don´t have to be applied to:


• existing software applications / software components which are stable and not
changed anymore

Exceptions to certain standards are possible but have to be well justified and approved by QA

Version: 1.0 - public - Page: 10 / 10


Copyright © WINCOR NIXDORF, 2010
Corporate Programming Standards - C/C++

3 Source Code Structure


The structure of source code has a deep impact on the readability and maintainability. To
achieve a uniform Wincor Nixdorf-wide C/C++ source code structure this chapter contains
several rules how the source code is to be structured.

3.1 Class structure: one .cpp and one .h(pp)


Each class must consist of exactly one header file (.h or .hpp, in the following we only write
.h), where it's declared, and must be defined in exactly one cpp-file. The file names must
match the class name, written in CamelCase.
Example:
• class MyHelper {…}
• MyHelper.h and MyHelper.cpp
Classes begin with upper case. Classes shall not begin with a module specific prefix, but ra-
ther be contained in a specific namespace, see also rule 3.5.
Abstract classes that have no implementation, but are used as base classes only, only have a
header file but no .cpp.
See [8]: "In my years at Microsoft working on large C++ projects, I've found that one thing that
made modularity (and testability) exceedingly difficult was having multiple classes jumbled to-
gether across arbitrary .cpp and .h files."

3.2 Header inclusion must be self-sufficient.


1) A header file must include all the header files necessary to parse this header: it must
not be necessary to include another header before your header, which means that
your header must not rely on any preceding inclusion.
2) A header file should only include the bare minimum number of header files neces-
sary to parse the header. This means that there are no more headers included than
necessary. This also means, that sometimes a forward declaration instead of a head-
er inclusion may be sufficient (if you only use a pointer to class “Example” you don’t
need to include Example.h. You can make a forward declaration instead)
To test these rules, you can write an one-line .cpp file, which only includes the header you
want to test. If you can successfully compile your .cpp you know at least, that your header
complies to rule 2. Afterwards you can check if your header complies to rule 3 by deleting
some includes in that header or by replacing them with forward declarations.

See also [6], which in fact references “Large-Scale C++ Software Design” by John Lakos.
See [5], chp. 23

3.3 Inclusion order


1) In a .cpp you include its own header first. (The only exception to this rule: if you use
precompiled headers then include them first.) .

Version: 1.0 - public - Page: 11 / 11


Copyright © WINCOR NIXDORF, 2010
Corporate Programming Standards - C/C++

2) Include a global header file (if it exists), which contains e.g. global defines or globally
used data structures. E.g. windows.h is a global header or there might be further
product/department-specific global header files.
3) Include the any other headers in a sequence from general headers to more special-
ized headers.

3.4 Inclusion guards


Header files must also be protected from multiple inclusions using the if-
ndef/define/endif construct in the header file.
/** \file cccom.xpp
\brief This proxy belongs to Communication Class.
This is a more detailed description, about this proxy. It can consist of several lines
and sentences.

\author Deve Loper //optional!


*/
#ifndef CC_COMMUNICATION_FW_XPP
#define CC_COMMUNICATION_FW_XPP
// interface code goes here
#endif

3.5 Use namespaces for API classes


If we include certain headers which have the same identifier for a class or a single variable,
we have no possibility by referencing the correct one. With namespaces we can avoid this
problem:
opengl.h:
namespace opengl {
class Vector3d {

//..
}
}

wincornixdorfGeometry.h:
namespace wincornixdorf {
class Vector3d {

//..
}
}

The cpp-file:
#include "opengl.h" //contains class “Vector3d”
#include "wincornixdorfGeometry.h" //this one, too!
//..
wincornixdorf::Vector3D myVec = new wincornixdorf::Vector3D(); //take Wincor
Nixdorf’s vector

This also avoids adding prefixes to the class names and identifiers of a public interface.
Namespaces shall begin with a small letter.

Version: 1.0 - public - Page: 12 / 12


Copyright © WINCOR NIXDORF, 2010
Corporate Programming Standards - C/C++

3.6 Class length and responsibility


Classes shall have one purpose only and therefore a class length (which means in fact the
length of the .cpp file) of 2000 lines (including comments) shall not be exceeded.
If the class is longer one should check if a refactoring should take place. For example utility
methods can be put into a new class. Methods that take care of special data can be put into a
single class.
Prefer minimal classes to monolithic classes. Small classes are easier to write, test and use.
Monolithic classes which try to solve a complex problem are hard to test, because everything
is intermingled and they violate the principle of encapsulation. Furthermore it’s not possible to
deliver a reasonable design diagram of that program, because it would only consist of one
block (= the monolithic class).
The later you begin taking care of your class design the harder it gets to prevent your code
from getting unreadable and unmaintainable.
See [5] chp. 33 and chp. 5.

3.7 Build without warnings


A project must build without warnings on the highest warning level. If explicit warnings can not
be avoided by a code change, warnings can normally be switched off by a #pragma which
surrounds the code snippet. Even if this does not solve the root of the problem, we are aware
of the problem, because the #pragma statement makes this obvious.

Version: 1.0 - public - Page: 13 / 13


Copyright © WINCOR NIXDORF, 2010
Corporate Programming Standards - C/C++

4 Names and declarations


Naming conventions make programs more understandable by making them easier to read.
They can also give information about the function of the identifier - for example, whether it's a
constant, package, or class - which can be helpful in understanding the code.

4.1 Naming Convention


Apart from the above notation rules, the following naming convention applies:
• Variables begin with a lower case character.
• Names should be formed from composite words, delimited by upper case letters, with
no underscores allowed. Each word except the first one is capitalised.
For example, ulCounter and sessionIds are acceptable variable names.

4.2 Declaration rules

4.2.1 Declare as locally as possible


Variables shall be declared as locally as possible for the following reasons:
• One gets smaller blocks of code that can easier get migrated into functions.
• Keeping track of changes to that variable is easier.
• Better performance.
“As locally as possible” means as well the scope in which a variable is declared, as
well the line in which a variable is declared: declare it where you first use it, don’t
declare every variable at the beginning of the scope.
See [2], chp. 2.1.
See [1], DCL07-CPP.
See [5], chp. 18

4.2.2 Sort variables by meaning


Object declarations should not be visually aligned, but have to be sorted by mean-
ing.
Example:
int iCoinValue = 0;
string strCoinDescr;

int iBillValue = 0;
string strBillDescr;

4.2.3 Use meaningful names


Variables shall receive meaningful names, which make comments (to the farthest
extent) unnecessary:
This…

Version: 1.0 - public - Page: 14 / 14


Copyright © WINCOR NIXDORF, 2010
Corporate Programming Standards - C/C++

int lengthInMM = 0;
…is better than this:
int length = 0; //in mm

4.2.4 One purpose only


Variables shall have one purpose only. They shall not be used differently if the con-
text changes.

4.2.5 One declaration per line


There must be only one declaration per line. Separate lines make it easier to find
the declaration of a particular variable name.

4.2.6 Don’t cover external declarations


Internal declarations must not cover external ones, because this is confusing. E.g.
USHORT usVar = 5; //external usVar
if (a > b) {
USHORT usVar = 3; //internal usVar, this must be avoided
//We can’t access the outer usVar anymore
}

See also [1], DCL01-CPP.

4.2.7 Use declarations in for-loops only in the loop


for (USHORT k = 0; k <= 5; k++) {
//do sth.
}

USHORT usStrange = k + 1; // k not known? VS6 and VS2003 will not complain!
// But even so, we forbid such usage of k
for (USHORT k = 100; k <= 109; k++) {//works for all compilers like ex-
pected
//a redefintion of k is okay here
//do sth.
}
In Visual Studio 6 and Visual Studio 2003 the variable “k” is still known after the
first for-loop. Visual Studio 2008 (and other compilers) will generate an error of you
use “k” after the for-loop (applies also to Java). However, with every compiler you
can redefine a “k” in a second for-loop.
Therefore a counter variable declared in the for-loop header shall not be used after
the loop has finished – even if the compiler does not throw an error. It may only be
used like above: With a new declaration in a second loop.

4.2.8 For-Loop counter


For-loops should never have an additional increment or decrement of the loop
counter inside the loop. If their use is necessary, clearly document the reasons.

Version: 1.0 - public - Page: 15 / 15


Copyright © WINCOR NIXDORF, 2010
Corporate Programming Standards - C/C++

4.2.9 While-loop counter


In a while loop, the increment or decrement should be at the top or bottom of the
block. Do not increment or decrement loop counter variables in the middle of a
block. This makes it harder to find the loop counter. If it is necessary, clearly doc-
ument the reasons.

4.3 Initialization

4.3.1 Initialize all variables


Variables must be initialized, best during definition.

4.3.2 One initialization per line


There must be only one initialization per line to maintain readability.
VOID nothing() {
USHORT usSum = 0; //okay
ULONG* pulPointer = NULL; //okay

USHORT usCounter; //no


USHORT usOne = 1, usTwo = 2; //no
//. . . .
}

MyType::MyType() {
usCounterM = 0; //yes
ulValueM1 = ulValue2M = 0; //no
}

If you use initializer lists for your constructor, write the variables in the order of their
declaration.

4.4 Class names are written in CamelCase


A class that handles some data is called SomeDataHandler. Don’t apply the prefix “C” to a
class (i.e. do not call it CSomeDataHandler), there’s no Hungarian notation for classes.

4.5 Function syntax rules

4.5.1 Prefixes for exported C functions


Exported C functions (not C++: use namespaces in C++) must be uniquely as-
signed to one module per prefix (a module can be a library or a set of interelated
functionality).
Example:
TimerStart, TimerStop in a timer library.
SyncStart, SyncStop in a synchronisation library.

Version: 1.0 - public - Page: 16 / 16


Copyright © WINCOR NIXDORF, 2010
Corporate Programming Standards - C/C++

This helps to avoid naming conflicts with equally named functions that are exported
in libraries.

4.5.2 No prefixes for C++ functions


C++ functions should not receive prefixes, but instead be included in a namespace
by which they can be referenced.

4.5.3 Meaningful names


Each function shall receive a meaningful name, which unmistakably describes its
purpose.
WCHAR* Conv2U(CHAR* strInput); // mmhhh..

//better:

WCHAR* ConvertToUnicode16Bit(const CHAR* strSourceString);

4.5.4 Function declaration


ANSI-C style should be used for function declaration, with parameter types in the
function declaration and a return type declared.
// For example use:
int power(int base, int n) {
//.......
}

//instead of:
power(base, n)
int base, n; {
//.......
}

4.6 #define syntax rules

4.6.1 The name of a define has to be module specific


No scope qualifiers (e.g. namespaces or classes) can be applied to a define. This
may lead to confusion if there are certain defines with the same name.
Example:
#define TIMER_MAX_VALUE 200

In the example TIMER is the prefix used by the timer module. Many other mod-
ules/libraries may have a define with the name MAX_VALUE, but not with the pre-
fix TIMER.

4.6.2 Redefinitions of macros are not permitted


Redefinitions of macros are not permitted.

Version: 1.0 - public - Page: 17 / 17


Copyright © WINCOR NIXDORF, 2010
Corporate Programming Standards - C/C++

4.6.3 Macro names are written in UPPERCASE


Macro names are written in uppercase. Multiple words are separated by an under-
score.

Version: 1.0 - public - Page: 18 / 18


Copyright © WINCOR NIXDORF, 2010
Corporate Programming Standards - C/C++

5 Design and programming rules


The present chapter summarizes a number of valuable learned lessons that can be applied in
new projects to improve almost every aspect of the development work, explaining, where nec-
essary, their particular relevance to the C/C++ language and programming environment.

5.1 Avoid global variables


Global variables (outside any scope) shall be avoided if possible and be replaced by static va-
riables in classes.
Reason: Global variables have no scope, so it’s not clear who’s responsible for them. They
have no access protection and can be changed by any module or class. This may also be a
security risk.
If there is no way around global variable, but this global variable shall only be used in file
scope, then declare it in an anonymous namespace.
See [1], DCL15-CPP. (regarding the anonymous namespace)
See [5], chp 10 (regarding the general rule, “Avoid shared data”)

5.2 Prefer the stack over the heap


This means that objects should not get created with "new" if we can avoid it. At least for locally
needed variables this should be possible. For all other reasons the STL often offers a con-
tainer that takes care of the heap management:
Instead of…
MyClass* pObj = new MyClass("Test"); //Heap -> delete necessary
CHAR* sText = new CHAR[len]; //get len during runtime
//..
delete pObj;
delete[] sText; //another source of error: to forget the brackets...

…better use:
MyClass Obj("Test"); //Stack -> no delete necessary
string strText(""); //an STL string with a dynamic length

This also implies that static arrays should be replaced by STL containers to manage the
memory dynamically. With this we also avoid access violations and buffer overflows. Espe-
cially static char arrays should be replaced by the STL string or by similar string classes.
See [2], chp. 4.5
Remark: For verly large objects this rule may not always be applicable, because the stack size
will be limited (e.g. 1MB for 32bit Windows).

5.3 Prefer new / delete


Prefer
• new/delete

Version: 1.0 - public - Page: 19 / 19


Copyright © WINCOR NIXDORF, 2010
Corporate Programming Standards - C/C++

• new[]/delete[]
over malloc() / free().
Additionally take care that you do not mix up the scalar versions of new / delete with the
vector versions, i.e. new[] and delete[]. If you use the vector version new[] to allocate
memory for an array, you have to take the vector version delete[] to free this memory (and
vice versa). If not, the behaviour of the compiler is undefined and you may encounter memory
leaks.
The same applies to mixtures of malloc / delete and new / free. Do not even think of using
these combinations, you will get undefined behaviour!

5.4 Prefer references as method arguments


If functions need to modify input data, references are preferred over pointers. If working with
pointers that get passed around, there's always the question who shall delete the object. With
references we don't have that problem, because:
• References always point to a valid object.
• No delete can be called on a reference
• A reference always points to the same object
• NULL is not defined for a reference.
Example:
MyClass Object;
MyClass& Ref1; //won't work, compiler error
MyClass& Ref2 = Object;

Of course you can also use references if you don’t want to modify the object. This can be the
case if the object is very large and shall not get copied (performance problems). In such a
case use const references, see 5.5.

5.5 Use const for immutable values


For immutable member (no matter if variables or function arguments), use the const qualifier,
for the following reasons:
• It’s safe. Immutable values must not be checked.
• It’s checked at compile-time if you violate that qualifier accidently, e. g. if you assign a
value to it, although this violates your intention
• The reader of the code quickly understands your intention as soon as he sees the
const definition.
void func(const Object& o, const int i) //example for function arguments

Also, avoid casting away the const qualifier except to call a const-incorrect function.
Specify whether a pointer itself is constant, the data it points to is constant, both or neither:
char* p1; // non-const pointer, non-const data
const char* p2; // non-const pointer, const data
char* const p3; // const pointer, non-const data
const char* const p4; // const pointer, const data

Version: 1.0 - public - Page: 20 / 20


Copyright © WINCOR NIXDORF, 2010
Corporate Programming Standards - C/C++

See [5], chp. 15 and 94.

5.6 Use const for read-only member functions


Member functions that do not modify any class data, shall be declared as const, due to the fol-
lowing reasons:
• a user quickly sees that a member function does not modify any class data
• it’s checked at compile-time if your member function modifies class data: if so, you will
get a compile error.

void getSomeValue(int index) const; //const declaration

5.7 Avoid Macros


The general rule is to avoid any macros, if possible. See [5], chp. 16.

5.8 Prefer “const” variables or enumerators over #define


Declarations of const variables shall be preferred over defines, because:
• For defines we don't get any debugging symbols and there's no type specification.
• Defines are out of any scope and there are no error messages which contain the iden-
tifier of the define.
Instead of
#define ASPECT_RATIO 1.653
#define NAME "Pit"
better
static const DOUBLE ASPECT_RATIO = 1.653;
static const CHAR NAME[] = "Pit";
Note that the name of the constant has to be written in uppercase characters. Underline char-
acters are used as delimiter between words.
Constants are always “const” and most likely “static”, however no “S” postfix (nor a “G” for
global, nor a “M” for member) has to be added.
See [2], chp. 7.5.1.

5.9 Avoid compiler switches


Compiler switches should be avoided and be replaced by runtime switches:
Instead of
#define STH_SPECIAL
#include <stdio.h>
INT main() {
#ifdef STH_SPECIAL
printf("Somethind special.\n");
#else
printf("Something ordinary\n");
#endif
return 0;
}

Version: 1.0 - public - Page: 21 / 21


Copyright © WINCOR NIXDORF, 2010
Corporate Programming Standards - C/C++

better
#include <stdio.h>
INT main() {
iSwitch = getBehaviourSwitch();
if (iSwitch == STH_SPECIAL) {
printf("Something special.\n");
}
else {
printf("Something ordinary.\n");
return 0;
}
}

Drawbacks of compiler switches:


• Bad readability
Macros that are used as compiler switches, degrade the readability of the code. In the
example above, the code which is embedded between the switches is only one line
long. But especially for more embedded code the readability gets worse.
If the same compiler switch is used at different locations in the code, the readability
and understanding of the code worsens even more.
If we use normal variables as switches, the code is more readable, because the em-
bedded code has the indention we expect. Furthermore we can easier search for oc-
currences of a variable, which is harder for occurrences of macros.
• Multiple compile activities
One compiler switch requires two compile activities, each activity results in a different
DLL or EXE. This requires more time and for each little code change we have to com-
pile the source code two times.
• More complicated tests
If the DLLs or EXEs are finally built, we have always have two DLLs or EXEs which
have to be tested. Instead of swapping a DLL/EXE and make every test a second
time, it’s easier to have a runtime switch, which is triggered during testing.
Sometimes compiler switches are used to distinguish between certain release specifications.
In such a case, a different release requires a different behaviour of a component, but it still
serves the same interface. In such a case, the developer should also think about a better ob-
ject-oriented design of his framework. For example the factory-pattern can be applied, which
makes a behaviour-decision possible at runtime.
See also [2] chp. 4.13

5.10 Prefer classes over structs


In C++ structs are the same as classes with public members/methods only. So structs can
contain (public) methods and members. However it’s a good coding convention to use structs
only in a C manner and not to implement methods in structs. If you are implementing a data-
type collection which also needs methods, then implement a class instead. This has the fur-
ther advantage that classes also require a single .cpp and .h file (which makes code more
readable) and classes can in future also implement private methods and members. This helps
encapsulating the code, whereas structs limit the usability.

Version: 1.0 - public - Page: 22 / 22


Copyright © WINCOR NIXDORF, 2010
Corporate Programming Standards - C/C++

5.11 Stay downward compatible


Every interface that is officially released and which can be used by customers of other de-
partments has to stay downward compatible.

5.12 Hide as much data as possible


Variables and methods of a class shall be declared as private if it’s not absolutely necessary
to access them from the outside. Variables that shall be exposed, should be made available
by set- and get-functions. With this, we can control the access to that variables. With a single
point of access, we can easily add traces to that method. So we can easily trace who sets that
variable in which order.
If variables and methods shall be available in derived classes, but need not to be exposed to
the outside, they shall be declared as protected.
See [2], chp. 14.1.5
See [1] OOP00-CPP.

5.13 Write virtual destructors for base classes


A base class should always have a virtual destructor. Without this
1) a dynamic_cast is not possible and
2) if we call "delete" on a derived class with help of a pointer of the base class, not all
memory is freed
So, always implement at least an empty method for the virtual destructor. If the class is virtual
(i.e. all methods are pure virtual) no .cpp file must be made for the empty method of the virtual
destructor.
Example:
class Mother {
public:
Mother() {};
// ~Mother() {}; //bad
virtual ~Mother() {}; //good!
};

class Child : public Mother {


public:
long* lBigBuffer;
Child() { lBigBuffer = new long[10000000];};
~Child() { delete[] lBigBuffer;};
};

void MotherChildTest() {
Mother* m = new Child(); //Allocates a lot of memory

delete m; //will not call ~Child() if ~Mother() is not virtual.


//Memory is not freed.
}

Version: 1.0 - public - Page: 23 / 23


Copyright © WINCOR NIXDORF, 2010
Corporate Programming Standards - C/C++

5.14 Method length


To keep track of the purpose of a method and to keep an easy overview of how the method
works, a method length of 120 lines should not be exceeded.
If the method contains a lot of traces or instructions that span over multiple lines, a method
can also be longer, but a method with several hundred lines is not a good style and not easily
maintainable. See[5] chp. 20.
Think of a general example:
• A method reads 10 different values out of the windows registry, stores them in internal
variables and afterwards triggers some other functions according to these values.
• Of course, you can do this all in one method, but with all the error logging and tracing
you can quickly exceed the 120 lines: For every value it has to be checked if it can be
read from the registry, and if not, the internal variables must take default parameters
etc.
• Well, why not extracting the three main purposes into three purposes into three new
functions?
Example:
VOID initialiseRegistryParameters() {
readRegistryParameters(refRegistryParameters);
fillInternalVariables(refRegistryParameters);
triggerAdditionalFunctions();
}
• Okay, with some logging and return value checking we will get more than three lines,
but even if we get 15 lines, a new developer immediately sees how this methods
achieves its goal Æ by just reading the names of the three methods that are called,
• In this example we also follow an advise by Robert C. Martin and also the Clean Code
Developer group: A method should have one level of abstraction, see [3] and [4].

5.15 Range checks on input data


Each function shall implement a range check on its input data to avoid overflows, truncation
errors or sign errors, no matter if the input data is a string or an integer.
This rule is a must-have for interfaces, and you should also stick to it for private functions.
Don't make assumptions on numeric input data, but perform range checks to avoid overruns
and/or truncations. Especially surround arithmetic terms and casts with range checks.
Unsafe (1):
ULONG ulSmallValue = getUserInput();
ULONG ulSum = ulSomeValue + ulSmallValue; //ulSmallValue really small enough?
Safe (1):
ULONG ulSmallValue = getUserInput();
if (ulSmallValue <= (MAX_ULONG - ulSomeValue)) {
ULONG ulSum = ulSomeValue + ulSmallValue;
}

Unsafe (2):
ULONG ulSmallValue = getUserInput();
doSomething( (USHORT) ulSmallValue );
Safe (2):

Version: 1.0 - public - Page: 24 / 24


Copyright © WINCOR NIXDORF, 2010
Corporate Programming Standards - C/C++

ULONG ulSmallValue = getUserInput();


if (ulSmallValue <= MAX_USHORT) {
doSomething( (USHORT) ulSmallValue) );
}

5.16 Avoid non-range-checking functions


Additional functions that don't perform range checking shall be avoided, like:
• strcpy()
• strcat()
• sprintf()
• vsprintf() or
• gets().
Better use
• strncpy() etc.
• strcpy_s() etc. (Microsoft specific)
• STL string or comparable string implementations.

Of course you can still make mistakes by using strncpy() etc. But if we compare strcpy() and
strncpy() you have to pass the length as parameter to strncpy(). This helps to remind you or
any other programmer that you have to think of the length of the variables. This does not au-
tomatically avoid errors, but it is a support to reflect upon the length of the string.

5.17 Return value validation


If a function is not defined as VOID, its return value should be evaluated by the caller.

5.18 Use sizeof


Let the compiler work out the length of objects: use sizeof rather than declaring structure
lengths explicitly.

5.19 Avoid machine dependent fill methods


Do not apply right shift (>>) or left shift (<<) operators to signed operands, and do not use
shifts to perform division or multiplication. Clearly noted exceptions are allowed.

5.20 Don’t trust the byte order


Avoid writing code that depends on the byte order of a particular architecture or that depends
on particular word alignment boundaries.

Version: 1.0 - public - Page: 25 / 25


Copyright © WINCOR NIXDORF, 2010
Corporate Programming Standards - C/C++

5.21 Pointer assignment


Pointer assignment shall be only between pointers of the same type (void * is an exception ,
though should be used only with good reason). Avoid treating pointers as integers or vice ver-
sa.

5.22 Pointer validity


To check the validity of a pointer, compare it to a typecast NULL. Do not use the integer 0.
Note that cstdio or stdio.h must be included to define NULL.

5.23 No sprintf on overlapping buffers:


sprintf is not allowed on overlapping buffers, because the behaviour is undefined.

char achTest[1024] = "TestString";


sprintf(achTest, "%s_appended", achTest);
This is forbidden, because it's undefined if we get "TestString_appended" or if the program
crashes.

5.24 new / delete and new[] / delete[] pairs must match


new/delete pairs have to be checked for proper use. For every new there must be a corre-
sponding delete. Make sure that delete[] is used on arrays. Class objects that are allo-
cated dynamically during runtime have to get deleted in the destructor at the latest.

5.25 Do not use goto


Do not use the keyword goto.

5.26 Avoid magic numbers


Don’t use constant values, better use enums or const values. This avoids comments on vari-
ous places and guarantees the assignment of a correct value in one single place.
//
//Ok:
//
const int SENSOR_1 = 25;
const int SENSOR_2 = 35;

switch(value) {
case SENSOR_1 : {
foo();
}
break;
case SENSOR_2 : {
bar();
}
break;
}

Version: 1.0 - public - Page: 26 / 26


Copyright © WINCOR NIXDORF, 2010
Corporate Programming Standards - C/C++

//
//NOT okay:
//
switch(value) {
case 25 ://Sensor 1
{
foo();
}
break;
case 35 ://Sensor 2
{
bar();
}
break;
}

Version: 1.0 - public - Page: 27 / 27


Copyright © WINCOR NIXDORF, 2010
Corporate Programming Standards - C/C++

6 Formatting and notation rules


This chapter describes the formatting layout for the C/C++ language elements. These all
share a set of common properties, so they will be described together and for readability all
called 'classes' here. Usually the formatting of the code is done by the integrated development
environment (e.g. Visual Studio) using customizable rules.

6.1 public / protected / private indention level


The keywords are written on the same indention level as the class keyword.

6.2 public / protected / private order


The keywords are organized in decreasing scope of audience: public, then protected,
then private. Client program designers need to know public members; designers of poten-
tial subclasses need to know about protected members; and only implementers of the class
need to know about private members and friends.
If you do not follow this rule, then at least all keywords shall appear only once: Don’t declare
private members, then declare public member and then declare private members again. This
is confusing.

6.3 class and namespace indention level


The class keyword is written on the same indention level as the namespace keyword:
namespace wincornixdorf
{

class Example { //same indention as “namespace”


public: //same indention as “class”
ULONG ulSomeData;
protected:

private:
}

6.4 Conditions in a control structure


If there is more than one condition in a control structure, they must be enclosed in brackets,
e.g.:
if ((sRc == 0) && (fNoMsg == FALSE))
Using parentheses (even when not required) helps to avoid errors caused by misunderstood
operator precedence.
Furthermore you shall not make any assumptions on the evaluation order of the conditions,
because different compilers will have different behaviours. “Shortcut evaluation” is tricky and
error prone:
if ((sRc == 0) && (getAndIncrementNoMsg() > 5))

Version: 1.0 - public - Page: 28 / 28


Copyright © WINCOR NIXDORF, 2010
Corporate Programming Standards - C/C++

Depending on sRc’s value in the example, the number of messages is increased or not. Avoid
such shortcuts.

6.5 Line length


Lines should not be too long (approx. 120 characters).

6.6 Curved brackets


• All statements within if- and else-statements must be bracketed using { and }.
• Empty statements must be written with empty brackets {}.
• Statements in defines must be enclosed in brackets.
#define DY__CLS {printf(DY__CLS_STRING);}
However, such defines should be avoided and shall be replaced by a "normal" func-
tion call.
• The pre-initialization list is written in the same line
• After a do-while loop, the while follows directly the closing bracket to allow better dif-
ferentiation.
• When initializing arrays, the substructures and subarrays must be indicated by brack-
ets ('{', '}').

6.7 Indent level


Four spaces are indented per nesting level. No tab jumps shall be used, because this leads to
annoying effects if source files are edited with different editors or (even worse) on different
operation systems.

6.8 Switch-case syntax

6.8.1 Each switch has a break


Each switch level must have a break. Exceptions must be commented using
• // NO BREAK
or
• // FALLTHROUGH

6.8.2 Always provide a default

Always provide a default for switch statements.

Version: 1.0 - public - Page: 29 / 29


Copyright © WINCOR NIXDORF, 2010
Corporate Programming Standards - C/C++

6.9 Break and continue


In loops, break and continue should be used carefully and be commented to make clear
why you return from this loop and where you go.

6.10 Blank usage

6.10.1 Use blanks around binary operators


Use blanks around binary operators that are surrounded by tokens, except “.” and
“->”.
a = b + c;
a++; // this is not a binary operator, just like --
pMyClass->ClassFunction();
myClass.ClassFunction();
if (a == b)
if (a & c != d)
if ((a && c) || (b && d))

6.10.2 Use a blank after commas in argument lists or value lists


ClassFunction(arg1, arg2, arg3)
short sArray[] = {10, 20, 30}

6.10.3 Use a blank after semicolons if it does not delimit a code line.
for (i = 0; i < 10; i++)

6.10.4 Use a blank after control flow statements.


if (...)
while (...)

6.11 Comment indention


Code comments which apply to a block of code (either a loop or branch construct, or a group-
ing of statements), should be immediately above the block and indented to the same level as
the code.
Code comments which apply to a single statement may be immediately above (without an
empty line) or to the right of the statement.

Version: 1.0 - public - Page: 30 / 30


Copyright © WINCOR NIXDORF, 2010
Corporate Programming Standards - C/C++

7 Documentation and commenting


The developer who must understand the code before implementing an enhancement or a de-
fect fix will appreciate the foresight in providing quality documentation. The documentation
should make the implemented functionality understandable with minimal analyzation of the
source code itself.
All comments have to be written in American English.
Normally more comments are always better than no comments in the code. Comments make
the code more clear and deepen the understanding of the code.
However, certain rules also apply to how and when to comment the source code, because
comments can also become confusing.

7.1 General rule: why, not what


Comments have to tell why sth. is done and not necessarily what. This goes hand in hand with
giving variables and methods meaningful names and with avoiding trivial comments. You can
heavily decrease your need for comments, if your variables and methods have meaningful
names.
Furthermore, instead of commenting large code blocks (in an even larger function), these
code blocks can be put into a new function with a meaningful name (so you also avoid too
long functions, see “Method length”).
See [4].

7.2 No trivial comments


Trivial comments are not allowed - this is not a “should-be-avoided” rule.
A trivial comment is a comment that (maybe continuously) comments one single line of code
to tell what is done.
Examples of trivial comments:
//Trace
TrcWritef(TRC_SHOP, “my trace”);

//Calculate the sum


iSum = iProduct1 + iProduct2;

Reason: Comment the “why” not “what”. Such trivial comments distract the reader of the code
and pollute the code with unnecessary remarks. If source code is read by a new programmer,
comments draw attention to themselves, because the reader expects an explanation of the
source code to deepen his understanding. Trivial comments draw attention to the wrong
places. Later on, the reader may not identify comments that really matter and explain some
complex piece of code.

7.3 Out-commented code blocks


Code blocks that get commented out from one revision to the next revision shall
• either be deleted (because they can still be seen in the content management system)

Version: 1.0 - public - Page: 31 / 31


Copyright © WINCOR NIXDORF, 2010
Corporate Programming Standards - C/C++

or
• there must be an additional explanation comment.
This has to explain
1) Why and when the code was commented out
2) Under which circumstances this code block can get removed completely in the
future or under which circumstances this code block shall be taken back into
the code.
Reason: Out commented lines are confusing, because a new developer does
not know if this code was important or unimportant, if an error may have sth.
to do with this out commented code block, and so he has to understand and
analyse this code block, too. He may even have to check this code block back
in, compile the program and check for a different behaviour!

7.4 Class description in the header (Doxygen-like)


Each class receives a description in the Doxygen format that looks like the following:
/** \class Test
* \brief This is a test class.
*
* Some details about the Test class
*/

The methods of the class (see 7.5) and the members of the class (see 7.6) must also be
commented in the header file.

7.5 Method description in the header (Doxygen-like)


Each method receives a documentation in the Doxygen format in the Classes’ header file:
/**
\brief Initialise Printer - resets the printer and returns the new status

Here we print the more detailed description of this function. There's no special com-
mand for the long description, there must only be a blank line between this and the
brief description.

\param[in] p_hdPeri - peripheral handle


\param[out] p_lpwStatut - status of the printer

\return WORD
API_OK - success
API_AVER_PERI - warning: read status sent by the
API_ERR_SYSTEME - an error occurred
API_ERR_PERI_ABSENT - peripheral or driver not installed
API_ERR_PERI_HORS_SERVICE - peripheral is not in service
API_ERR_PERI_HANDLE - invalid peripheral handle
*/
This header is readable by Doxygen, which can automatically parse all sources and produce
an API description.
This also and especially applies to methods in public interfaces. This helps to keep the docu-
mentation up-to-date.
Note: if you put a # before the return value (e.g. “#API_OK” instead of API_OK) this return
value gets automatically linked if you produce a documentation later. This means that you can
click on “API_OK” in the documentation and you will jump to the definition of API_OK.

Version: 1.0 - public - Page: 32 / 32


Copyright © WINCOR NIXDORF, 2010
Corporate Programming Standards - C/C++

7.6 Comment members of a class Doxygen-like


At least if variables are members of a class, they have to be commented in Doxygen format in
the classes’ header file.
BOOL fInitM; //!< TRUE : if init was called

7.7 Beginning comments


Each source file (.c, .cpp, .h, .hpp, etc.) must contain a header in which the module (file name
and contents) is described briefly in doxygen format.
/** \file cccom.xpp
\brief This proxy belongs to Communication Class.
This is a more detailed description, about this proxy. It can consist of several lines
and sentences.

\author Deve Loper //optional!


*/
#ifndef CC_COMMUNICATION_FW_XPP
#define CC_COMMUNICATION_FW_XPP
// interface code goes here
#endif

Mandatory keywords:
• \file
• \brief
Following the \brief keyword, a mandatory (!) long description follows in a new
line.
Optional Keyword:
• \author
If this is given, the \author should be the responsible developer(s) and not the initial au-
thor(s) of that interface.
These comments are not necessary if a file contains only the declaration (.h) or the implemen-
tation (.cpp) of a class, because in this case the purpose of the file (and therefore the purpose
of the class) is described in the doxygen documentation of the class (with the \class key-
word).

7.8 Comment #includes in public interfaces


When using includes in public interfaces, it should be noted what is included:
#include <stdio.h> //Standard includes (search path only)
#include "myinc.h" //Individual includes (no search path)

Version: 1.0 - public - Page: 33 / 33


Copyright © WINCOR NIXDORF, 2010
Corporate Programming Standards - C/C++

8 Guidelines for unit testing


Unit testing is a software verification and validation method in which a programmer tests if in-
dividual units of source code are fit for use. A unit is the smallest testable part of an applica-
tion.
If you are writing unit tests or if you are intending to write unit tests, then there are some rules
in this document, that shall be explicitly repeated here. Because no matter which framework or
which technique is used for unit testing, if you do not apply to these rules then unit testing can
become very hard.
• 3.1 Class structure: one .cpp and one .h
See the citation at that paragraph
• 3.6 Class length and responsibility
Monolithic classes which fulfill a lot of different tasks are harder to test, because their
purpose is not qualified. Keep a class simple to make more exact tests on that class.
• 5.1 Avoid global variables
Global variables have no scope and no access protection (or access mechanism at
all). If a class makes use of global variables you have to check if a unit test for that
class also has to check the state of the global variable. Such a global variable may be
contained in another .cpp or .h and all this different possibilities may make it tricky for
the unit test to access that variable.
• 5.9 Avoid compiler switches
Using compiler switches in your classes (to have a different behaviour during compila-
tion time) makes it necessary to use that compiler switches in your unit tests, too. If
you do this, you have to compile your unit tests with different compiler switches, too,
and you have to execute your tests at least two times. You can avoid this if you use
runtime switches. With runtime switches you can change the behaviour on-the-fly and
only have to execute your tests one time.
• 5.12 Hide as much data as possible
Hiding as much data as possible also hides data from your unit test implementation.
So you have less data that has to be tested, i.e. you have less functions to be called
and less variables to be manipulated or polled.
• 9.9 Prefer composition over inheritance
Loose coupling of components makes testing easier, because you have a better en-
capsulation of behaviour.

Version: 1.0 - public - Page: 34 / 34


Copyright © WINCOR NIXDORF, 2010
Corporate Programming Standards - C/C++

9 Best Practices
In this chapter you will find some best practices and some reminders, which help to avoid
some pitfalls and which can lead to a better design. There could be of course dozens of rules
here – for more information and best practices refer to some interesting books like [5] and [9].

9.1 Distinguish between prefix and postfix forms of increment and dec-
rement operators when overloading operators
// prefix form: increment and fetch
UPInt& UPInt::operator++() {
*this += 1; // increment
return *this; // fetch
}

// postfix form: fetch and increment


const UPInt UPInt::operator++(int) {
UPInt oldValue = *this; // fetch
++(*this); // increment
return oldValue; // return what was fetched
}
You can replace most of the postfix form with prefix form, except in []:
gzArray[++index] which is not gzArray[index++];

9.2 Define class type variables using direct initialization rather than
copy initialization.
In constructing both objects 'a1' and 'b1', a temporary String( "Hello" ) is constructed first,
which is used to copy construct the objects. On the other hand, for 'c1' only a single construc-
tor is invoked. Note, some compilers may be able to optimise construction of 'a1' and 'b1' to be
the same as 'c1'; however, conversion rules would still apply, e.g. at most one user-defined
conversion.
String a1 = "Hello"; // avoid
String b1 = String( "Hello" ); // avoid
String c1( "Hello" ); // prefer

9.3 The #define pre-processor directive shall not be used to create in-
line macros. Inline functions shall be used instead.
Inline functions do not require text substitutions and are well-behaved when called with argu-
ments (e.g. type-checking is performed). Example: Compute the maximum of two integers.
#define max (a,b) ((a > b) ? a : b) // Wrong: macro

inline int32 maxf (int32 a, int32 b) { // Correct: inline function


return (a > b) ? a : b;
}

y = max (++p,q); // Wrong: ++p evaluated twice


y = maxf (++p,q); // Correct: ++p evaluated once and type checking
// performed. (q is const)

Version: 1.0 - public - Page: 35 / 35


Copyright © WINCOR NIXDORF, 2010
Corporate Programming Standards - C/C++

9.4 Do not define a class template with potentially conflicting methods.


Defining a template with potentially conflicting methods will cause problems with some instan-
tiations of that template.
template< typename T >
class A {
public:
void foo( T );
void foo( int );
};

template class A< int >; // error void foo(int) declared twice

9.5 Only instantiate templates with template arguments which fulfill the
interface requirements of the 'template'.
Using a template argument where some of the requirements for the argument are not met may
cause compilation errors. Implicit instantiation only occurs for the parts of a template definition
that are used.
If an instantiation error is contained in a function definition that is not called then the error will
not be seen unless maintenance leads to that function being called. Explicit template instantia-
tion will instantiate all parts of the template definition, ensuring that the template argument is
valid.

class person {
public:
int getAge( void );
};

template < class T >


class singleVal {
public:
bool isMatch( T t ) {
return ( singleton == t );
}
private:
T singleton;
};

void foo( person const& other ) {


singleVal< person > emperor; // no error as isMatch not yet called

if ( emperor.isMatch( other ) ) // instantiation error,


{} // no 'op==' for person
}

// explicit instantiation of complete template definition


//
template class singleVal< person >; // error! no op== for person

9.6 Use empty() instead of checking size() against zero.


Testing empty() and comparing size() to zero are the same thing, however for some contain-
ers it is expensive to calculate the number of elements so it is less efficient to compare the
size to zero. It is always better to use empty when testing if a container has elements.
std::list< Node > myList;

if ( myList.empty() ) { // constant time test

Version: 1.0 - public - Page: 36 / 36


Copyright © WINCOR NIXDORF, 2010
Corporate Programming Standards - C/C++

doSomething();
}

if ( 0 == myList.size() ) { // linear complexity operation


doSomething();
}

9.7 Use Standard Template Library containers and algorithms in pref-


erence to custom designs.
The STL forms part of the language standard and represents a well-tested library of re-usable
code.

9.8 Never modify the key part of a set or multiset element.


Sets and multisets (e.g. std::map and std::multimap of the STL) sort elements as they
are inserted into the container, therefore any change to an element that affects its sort position
will corrupt the container and result in very hard to find bugs.

9.9 Prefer composition over inheritance


Making complicated inheritance structures does not automatically mean that you are a making
a clever OO design.
In general, let your class Child inherit from a base class Mother if
• class Child is also treated like a class Mother by other callers (inheritance is most
often an “is-a” relation). Here a Child is also a Mother, because Child inherits all
functionality of Mother and therefore inherits the public interface of Mother. This
makes it possible for callers of Child to use only the public interface of Mother on
the Child class.
• class Child behaves like a class Mother. Because we have a “is-a” relation between
Child and Mother, Child shall also behave like its base class Mother. Do not
override functions and let them do tasks, which totally differ from their original imple-
mentation. So, inheritance shall also be “behaves-like-a” relation.
Do not let classes inherit from a base class, if such a base class only implements helper func-
tions for that child classes. First of all, such a structure breaks the rules above. Second, such
an inheritance makes the design harder to understand: if someone has to understand your
code, he can not concentrate on the child class itself, but has to understand fully the base
class, too, because all behaviour of the base class is contained in the child class.
In such a case, implement a helper class that is accessed in a normal way by all the classes
that need that functionality. You have better encapsulation and you do not pollute your original
classes. For new developers it’s easier to understand your class, because they concentrate on
the real implementation of your class: because the helper functions are not inherited, but are
contained in a helper class that’s composed with your classes, they can blank out the helper
class.
Such a loose coupling makes it also easier to transfer code, to test it and to maintain it, be-
cause you class design is not as intermingled as it is with a (more complicated) inheritance
design.

Version: 1.0 - public - Page: 37 / 37


Copyright © WINCOR NIXDORF, 2010
Corporate Programming Standards - C/C++

9.10 Do not use implicit casting


In C++, instead of implicit C-style casting, for example:
char * a = 0;
int b = (int) a;
only explicit casts using appropriate operators are to be used, i.e.
• static_cast

• dynamic_cast

• reinterpret_cast

• const_cast

Using these, the programmer’s intention becomes much clearer and less error-prone. In the
example above, the following code
char * a = 0;
int b = static_cast<int>(a);
would lead to a compiler error, because there is no legal way for converting a pointer to an in-
teger. In such a case, the programmer would be forced to use the reinterpret_cast operator
and therefore think twice when deciding.

9.11 Use explicit in single-parameter constructors


In order to avoid ambiguities, the keyword explicit should be used in constructors which ac-
cept a single parameter of a basic data type. For example, the following code:
class CharBuffer {
CharBuffer (int initialLength);
...
}
...
CharBuffer buf = ‘r’;
would be possible. The created instance of the CharBuffer class would not contain a single
character “r”, as maybe expected by the programmer. It would most probably be empty with
the initial length of static_cast<int>(‘r’).
The keyword explicit helps in avoiding such confusions:
class CharBuffer {
explicit CharBuffer (int initialLength);
...
}
...
CharBuffer buf = ‘r’; // compiler error
CharBuffer buf = CharBuffer(10); // correct

Version: 1.0 - public - Page: 38 / 38


Copyright © WINCOR NIXDORF, 2010
Corporate Programming Standards - C/C++

9.12 Be careful when using unsigned numbers in loops


When unsigned basic data types (int, long, byte) are used in loops, a great care is recom-
mended. For example, the following loop:
for (unsigned int i=11; i > 0; i -= 2) {
...
}
would most probably take much longer to complete than expected. Be aware of the fact that
the unsigned data type size_t from the STL is often quite popular choice for indexing.

Version: 1.0 - public - Page: 39 / 39


Copyright © WINCOR NIXDORF, 2010
Corporate Programming Standards - C/C++

10 Check List for Source Reviews


The following checklists can be used for manual and automated checking and reviews of the
source code, as part of the Early QA code review process.
NA is for “not applicable”.

10.1 Source Code Structure


Rule ID Not
Rule Fulfilled NA
Fulfilled
.cpp and .h per class. Does each class consist of exactly
3.1
one .cpp and one .h file?
All headers included. Does each header file include all
3.2 necessary headers to parse that header file? Does a
header file include bare minimum number of headers?
Inclusion order. Does every .cpp include its own header
3.3
first?
Inclusion guards. Is each header file protected from
3.4 multiple inclusion by using the ifndef/define/endif construct
in the header file?
Use namespaces for API classes. Are the the
3.5 namespaces used in case of an inclusion of headers which
have the same identifier for a class or a single variable?
Class length and responsibility. Does a class length not
3.6
exceed 2000 lines?
Build without warning. Does it build without warnings on
3.7
warning level 4?
Table 6 Source Code Structure Check List

10.2 Names and Declarations


Rule ID Not
Rule Fulfilled NA
Fulfilled
Naming Convention. Do all the variables begin with lower
4.1
case character?
4.2 Declaration Rules
Declaration. Are all variables being declared as locally as
4.2.1
possible?
Sort variables by meaning. Are all the variables sorted by
4.2.2
meaning?
4.2.3 Declaration. Do all variables have meaningful names?
4.2.4 Declaration. Do all variables have one purpose only?
One declaration per line. Is there only one declaration per
4.2.5
line?
Declaration scope. Have internal declarations covered
4.2.6
external ones?
Declaration in for-loops only used in loops. Have
4.2.7 variables being declared in the for-loop header been used
only in the loop?
4.2.8 For loop counter. Additional increment and decrement of

Version: 1.0 - public - Page: 40 / 40


Copyright © WINCOR NIXDORF, 2010
Corporate Programming Standards - C/C++

Rule ID Not
Rule Fulfilled NA
Fulfilled
the loop counter inside the loop is avoided?
While loop counter. Is the increment or the decrement of
4.2.9 the loop counters done at the beginning or at the bottom of
the block?
4.3 Initialization
Initialize all variables. Are all variables initialized during
4.3.1
definition?
One initialization per line. Is there only one initialization
4.3.2
per line?
Class name syntax. Are all class names written in
4.4
CamelCase?
4.5 Function syntax rules.
Prefixes for exported C functions. Have exported C
4.5.1 functions (not C++) been uniquely assigned to one module
per prefix?
No prefixes for C++ functions. Have prefixed for C++
4.5.2 functions been avoided and are instead included in a
namespace?
Meaningful names. Have all functions received meaningful
4.5.3
names, which unmistakably describe their purpose?
Function declaration. Is ANSI-C style used for function
4.5.4 declaration, with parameter types in the function declaration
and a return type declared?
4.6 #define syntax rules
The name of a define has to be module specific. Do the
4.6.1
defines have names, which are module specific?
Redefinition of macros is not permitted. Is the
4.6.2
redefinition of macros avoided?
Syntax of macro names. Are all the macro names written
4.6.3
in uppercase?
Table 7 Names and Declarations Check List

10.3 Design and programming rules


Rule ID Not
Rule Fulfilled NA
Fulfilled
Avoid global variables. Have global variables been
5.1
avoided as much as possible?
Prefer the stack over the heap. Has object creation by
5.2
using “new” being avoided as much as possible?
New / delete. Has new/delete been preferred over
5.3
malloc/free?
References as method arguments. Have references been
5.4 preferred over pointers when functions need to modify input
data?
Use const for immutable values. Has the const qualifier
5.5
been used for immutable members?
Use const for read-only member functions. Are the
5.6 member functions which do not modify any class data,
declared as const?
5.7 Avoid Macros. Have macros been avoided?

Version: 1.0 - public - Page: 41 / 41


Copyright © WINCOR NIXDORF, 2010
Corporate Programming Standards - C/C++

Rule ID Not
Rule Fulfilled NA
Fulfilled
Prefer “const” variables or enumerators over #define.
5.8 Have defines being used although const variables would
have been the better alternative?
Avoid compiler switches. Have compiler switches been
5.9
used although runtime switches would have been possible?
Prefer classes over structs. Are classes preferred instead
5.10
of structs in C++ codes?
Downward compatibility. Has every interfaced kept
5.11
downward compatible?
Hide as much data as possible. Have variables and
5.12 methods of all classes been declared as private wherever
this is possible?
Virtual destructors for base classes. Do all base classes
5.13
have virtual destructors?
Method length. Has a method length exceeded 120 lines
5.14
of code?
Range checks on input data. Has each function
implemented a range check on its input data to avoid
5.15
overflows, truncation errors and sign errors, no matter if the
input data is a string or an integer?
Avoid non-range-checking functions. Have all functions
5.16 that don't perform range checking been avoided? (e.g.
strcpy(), strcat(), sprintf(), vsprintf(), gets())
Return value validation. If a function is not defined as
5.17
VOID, is its return value being evaluated by the caller?
Use sizeof. Is sizeof used instead of declaring structure
5.18
lengths?
Avoid machine dependent fill methods. Is the application
of right shift (>>) or left shift (<<) operators to signed
5.19
operands avoided? Is the usage of shifts to perform division
or multiplication avoided?
Don’t trust byte order. Is the writing of code which
5.20 depends on byte order of another architecture or on
particular word alignment boundaries avoided?
Pointer Assignment. Is the assignment of pointers done
5.21
between pointers of same type?
Pointer Validity. Is the validity of a pointer checked by
5.22
comparing it to a typecast NULL?
No Sprintf on overlapping buffers. Has sprintf been used
5.23
on overlapping buffers?
5.24 New[] / delete[]. Was delete[] used for the array new[]?
5.25 Goto. Is the usage of goto avoided?
Avoid magic numbers. Is the usage of constant values
5.26
avoided?
Table 8 Design and programming rules Check List

Version: 1.0 - public - Page: 42 / 42


Copyright © WINCOR NIXDORF, 2010
Corporate Programming Standards - C/C++

10.4 Formatting and notation rules


Rule ID Not
Rule Fulfilled NA
Fulfilled
Indention. Are the keywords written on the same indention
6.1
level as the class keyword?
Public / protected / private order. Are the keywords
6.2
organized in decreasing scope of audience?
Indention. Is the class keyword written on the same
6.3
indention level as the namespace keyword?
Conditions. If there is more than one condition in a control
6.4
structure, have they been enclosed in brackets?
Line length. Do the lines of code exceed approx. 120
6.5
characters?
Curved Brackets. Are all statements within if- and else-
statements bracketed using {and}. Are empty statements
written with empty brackets { }? Are the statements in de-
6.6 fines enclosed in brackets? Are the brackets following di-
rectly the while in a do-while loop? Are the substructures
and subarrays indicated by brackets ('{', '}') when initializing
arrays?
Indention. Have four spaces been used per nesting level
6.7
and no tab jumps?
6.8 Switch-case syntax
Switch break. Does each switch level have a break or a
6.8.1
comment //NO BREAK?
Always provide a default. Is default provided for switch
6.8.2
statements?
Break and continue. In loops, have break and continue
6.9 only been used in order to avoid additional break
parameters and are they commented?
6.10 Blank Usage
Use blanks around binary operators. Are the blanks used
6.10.1
around binary operators which are surrounded by tokens?
Use a blank. Is a blank used after commas in argument or
6.10.2
value lists?
Use a blank. Is a blank used after semicolons if it does not
6.10.3
delimit a code line?
6.10.4 Use a blank. Is a blank used after control flow statements?
Comment indention. Are the code comments which apply
6.11 to a block of code, immediately above the block and in-
tended to the same level as the code?

Table 9 Formatting and notation rules Check List

10.5 Documentation and commenting


Rule ID Not
Rule Fulfilled NA
Fulfilled
General rule: why, not what. Do the comments tell why
7.1
something has been done?
7.2 No trivial comments. Have trivial comments been used?
7.3 Out-commented code blocks. Have all blocks that have

Version: 1.0 - public - Page: 43 / 43


Copyright © WINCOR NIXDORF, 2010
Corporate Programming Standards - C/C++

been commented out received a comment why and when


this has been done?
Class description in the header (Doxygen-like). Does
7.4 each class have a description in the Doxygen style in its
header file?
Method description in the header (Doxygen-like). Has a
7.5 Doxygen-like documentation in the Classes’ header file
been included for each method?
Comment members of a class. Are the variables which
7.6 are members of a class, commented in Doxygen format in
the classes’ header file?
Beginning Comments. Does each source file contain a
7.7 header in which the module is described briefly in Doxygen
format?
Comment #includes in public interfaces. Is the
7.8 information of what is included present when using
includes in public interfaces?
Table 10 Documentation and commenting Check List

Version: 1.0 - public - Page: 44 / 44


Copyright © WINCOR NIXDORF, 2010
Corporate Programming Standards - C/C++

A 1 List of Tables
Table 1 Document Distribution List ........................................................................................................6
Table 2 Document Editors ......................................................................................................................7
Table 3 Document Status .......................................................................................................................7
Table 4 Document History ......................................................................................................................7
Table 5 Document Reviews ...................................................................................................................7
Table 6 Source Code Structure Check List ..........................................................................................40
Table 7 Names and Declarations Check List .......................................................................................41
Table 8 Design and programming rules Check List .............................................................................42
Table 9 Formatting and notation rules Check List................................................................................43
Table 10 Documentation and commenting Check List.........................................................................44

Version: 1.0 - public - Page: 45 / 45


Copyright © WINCOR NIXDORF, 2010
Corporate Programming Standards - C/C++

A 2 Referenced Documents
[1] CERT C++ Secure Coding Standard
https://www.securecoding.cert.org/confluence/display/cplusplus
[2] Peter Thömmes: “C++ Notizen”, Online PDF, Version 2007-11-28
http://www.notes-about-cpp.com
[3] Robert C. Martin: “Clean Code: A Handbook of Agile Software Craftsmanship”, Prentice Hall
International
[4] Clean Code Developer
http://www.clean-code-developer.de/
[5] Herb Sutter, Andrei Alexandrescu: “C++ Coding Standards”, Addison-Wesley
[6] Noel Llopis, Physical Structure and C++ – Part 1: A First Look (seen 2010-02-16)
http://gamesfromwithin.com/physical-structure-and-c-part-1-a-first-look
[7] Doxygen - Source code documentation generator tool
http://www.stack.nl/~dimitri/doxygen/index.html
[8] Simplified Unit Testing for Native C++ Applications
http://msdn.microsoft.com/en-us/magazine/cc136757.aspx
[9] Scott Meyers, “Effective C++ (Third Edition)”, Addison-Wesley

Version: 1.0 - public - Page: 46 / 46


Copyright © WINCOR NIXDORF, 2010

You might also like