An QL Coding Standards
An QL Coding Standards
Document Revision J
April 2013
Table of Contents
1 Goals..................................................................................................................................................................... 1
2 General Rules....................................................................................................................................................... 1
3 C/C++ Layout........................................................................................................................................................ 2
3.1 Expressions................................................................................................................................................... 2
3.2 Indentation..................................................................................................................................................... 3
3.2.1 The if Statement.................................................................................................................................. 4
3.2.2 The for Statement............................................................................................................................... 4
3.2.3 The while Statement........................................................................................................................... 4
3.2.4 The do..while Statement..................................................................................................................... 5
3.2.5 The switch Statement......................................................................................................................... 5
3.2.6 Function Definition.............................................................................................................................. 5
3.2.7 C++ Class Declaration........................................................................................................................ 5
3.3 Commenting.................................................................................................................................................. 6
3.4 Module Layout............................................................................................................................................... 7
3.4.1 Header Comment................................................................................................................................ 7
3.4.2 Included Header Files......................................................................................................................... 7
3.4.3 Public Section Specification................................................................................................................ 7
3.4.4 Package Section Specification............................................................................................................ 8
3.4.5 Local Section Specification................................................................................................................. 8
3.4.6 Implementation Section...................................................................................................................... 8
3.4.7 Notes Section...................................................................................................................................... 9
4 Exact-Width Integer Types................................................................................................................................ 10
5 Names................................................................................................................................................................. 11
5.1 Reserved Names......................................................................................................................................... 11
5.2 Naming Conventions................................................................................................................................... 11
6 Object Oriented Programming in C.................................................................................................................. 13
6.1 Encapsulation.............................................................................................................................................. 13
6.2 Inheritance................................................................................................................................................... 14
7 Design by Contract............................................................................................................................................ 15
8 C/C++ Codesize Metrics.................................................................................................................................... 16
9 Related Documents and References................................................................................................................ 17
10 Contact Information......................................................................................................................................... 18
Copyright 2002-2013
Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free
Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with this
copyright notice being preserved. A copy of the license is available from the Free Software Foundation at:
www.gnu.org/copyleft/fdl.html.
Goals
Adopting a reasonable coding standard is perhaps the first and easiest step towards improving quality of
code, increasing maturity level, or achieving any code certification. The following coding guidelines are
intended to improve code portability, readability, uniformity and maintainability for software. The primary
objective of this Coding Standard is to boost software productivity and lower maintenance cost by
promoting commonality and avoiding misinterpretations and guessing. The Standard is designed mostly
with embedded systems in mind and, where applicable, recommends rules established by Motor Industry
Software Reliability Association (MISRA) [MISRA 04,12].
General Rules
The rules in this category are intended for better source code portability and consistent code rendering on
a wide variety of devices and platforms like: different screens, printers, and various code editors working
on different computer platforms. These rules should apply to all ASCII documents, not only strictly to
code.
No tabs are allowed in the source code because tabs are rendered differently on different devices and
bring only insignificant memory savings. Preferably, tabs should be disabled at the editor level. At the
very least, they should be replaced by spaces before saving the file.
Source code lines should never exceed 78 columns, and not even white characters (spaces or
tabs) are allowed past the 78th column. Limiting the column-count is intended to enable side-by side
editing and side-by-side differencing of code without horizontal scrolling of the text. (As all GUI
usability tests agree, horizontal scrolling of text is always a bad idea.) In practice, the source code is
very often copied-and-pasted and then modified, rather than created from scratch. For this style of
editing, its very advantageous to see simultaneously and side-by-side both the original and the
modified copy. Also, differencing the code is a routinely performed action of any VCS (Version Control
System) whenever you check-in or merge the code. Limiting the column count allows to use the
horizontal screen real estate much more efficiently for side-by-side-oriented text windows instead of
much less convenient and error-prone top-to-bottom differencing.
All source code should consistently use only one end-of-line convention. For improved portability,
this Standard recommends consistent use of the Unix end-of-line convention, with only one LF
character (0x0A) terminating each line. The DOS/Windows end-of-line convention with CR, LF
character pair (0x0D, 0x0A) terminating each line is not recommended because it causes compilation
problems on Unix-like systems, such as Linux. (Specifically, the C preprocessor doesnt correctly
parse the multi-line macros.) On the other hand, most DOS/Windows compilers seem to tolerate the
Unix EOL convention without problems.
Highly portable source code intended for wide use on different platforms should be limited to the old
DOS 8.3 convention for file and directory names. This restriction is imposed to allow using older tools
like embedded cross-compilers, linkers etc. still working in the DOS environment. The 8.3 file name
convention seems to be the least common denominator supported by all computer platforms.
All source code should use only lower-case names for files and directories. This restriction
promotes portability, because it eliminates the possibility of inconsistencies in the names. For
example, a Unix-like system might not include correctly a file qevent.h when the file name is
actually QEvent.h.
1 of 18
Quantum Leaps
C/C++ Coding Standard
C/C++ Layout
3.1
Expressions
The following binary operators are written with no space around them:
->
me->foo
s.foo
[]
Array subscripting
a[i]
()
Function call
foo(x, y, z)
Parentheses after function names have no space before them. A space should be introduced after each
comma to separate each actual argument in a function. Expressions within parentheses are written with
no space after the opening parenthesis and no space before the closing parenthesis. Terminating
semicolons should follow the instructions immediately with no space(s) before them:
strncat(t, s, n);
The unary operators are written with no spaces between them and their operands:
!p
~b
++i
j--
(void *)ptr
*p
&x
-k
The binary operators are preceded and followed by one (1) space, as is the ternary operator:
c1 == c2
x + y
i += 2
n > 0 ? n : -n
The keywords if, while, for, switch, and return are followed by one (1) space:
return foo(me->x) + y;
In case of compound expressions, parenthesizing should be used whenever the precedence is not
"obvious". In general, over parenthesizing is recommended to remove any doubt and guessing. In the
extreme case of MISRA-C Rules [MISRA 98], no dependence should be placed on Cs operator
precedence whatsoever (MISRA-C rule 47), so every expression must be parenthesized. In addition,
MISRA rules require that the operands of && and || shall be primary expressions (MISRA-C rule 34).
Following are examples of parenthesizing consistent with the strict MISRA-C rules:
(a < b) && (b < c) /* operands of && are primary expressions (MISRA rule 34) */
x = (a * b) + c;
/* dont rely on precedence of *over + */
2 of 18
Quantum Leaps
C/C++ Coding Standard
3.2
Indentation
All indentations must be exactly four (4) spaces to indicate scope. All declarators and control statements
are formatted according to the indentation style commonly known as the K&R sytle, Stroustrup Variant
[Stroustrup 10] and looks as follows:
<declarator | control statement> {
<statement>;
. . .
}
where the <declarator | control statement> may be one of the following:
function declarator
structure/class declarator
enumeration
structure/array initializer
The Standard requires that the statement following any of the keywords (if, else, while, for,
switch, case, do) must be compound, that is, use of braces is obligatory. This requirement
corresponds to MISRA-C rule 59. Although not strictly required by the C/C++ syntax, this rule is imposed
to remove any doubts as far as statement nesting is concerned, and to allow easy addition/removal of
nested statements with minimal differences showing when differencing the code using a VCS. For
example, consider adding a statement to a while loop:
/* not a compound statementnot recommended */
while (i > 0)
*t++ = *s++;
/* compound statement-recommended */
while (i > 0) {
*t++ = *s++;
}
after modification:
/* not a compound statementnot recommended */
while (i > 0)
*t++ = *s++;
--i;
/* compound statement-recommended */
while (i > 0) {
*t++ = *s++;
--i;
}
With the not-compound statement case you either make a mistake by forgetting the braces (although the
indentation clearly indicates the intention), or you must introduce the braces, which then show as a big
difference when merging the code or checking it into the VCS.
If the <declarator | control statement> is so complex that it cannot fit in one line, then it should be
formatted in the following manner:
<declarator | control statement ...>
<... declarator | control statement ...>
<... declarator | control statement>
{
<statement>;
. . .
Copyright Quantum Leaps, LLC. All Rights Reserved.
3 of 18
Quantum Leaps
C/C++ Coding Standard
}
The arguments of a declarator should be split into separate lines leaving separating comma , as the last
character in the line. The condition of the control statement should be split into separate lines starting new
lines with a binary operator. This formatting intends to avoid confusing continuation of the control
statement with its body. For example:
if (!decodeData(&s, &dataType,
&format, &version)
&& format != 2
&& version != 1)
{
log("data corrupt");
}
4 of 18
Quantum Leaps
C/C++ Coding Standard
Any fall though cases must be documented with comments confirming intentional fall through rather then
an omission.
// ctor
// xtor
// method
protected:
virtual void *bar();
private:
Copyright Quantum Leaps, LLC. All Rights Reserved.
5 of 18
Quantum Leaps
C/C++ Coding Standard
3.3
Commenting
Code implements an algorithm; the comments communicate the codes operation to yourself and others.
Adequate comments allow you to understand the systems operation without having to read the code
itself.
Comments can be generally divided into three categories:
Elaborate high-level comments for major software components like: modules, classes, and
exported APIs.
Comments in the first category explain high level interfaces and the code structure. With help of automatic
documentation generating tools like JavaDoc for Java or DOC++ for C/C++, these comments can easily
be turned into online (HTML) documentation. The Standard does not require that every top-level comment
be verified in view of converting it into on-line documentation. However, adhering to the following simple
rules will make such automatic documentation extraction much easier, if we want to take advantage of it:
Top-level comments should always come before the commented object.
No right-edge in comment boxes should be used, because keeping the right-edge of the box aligned is
counterproductive:
/* INCORRECT: */
/*****************************************************************************
* this is class Foo
*
* . . .
*
*****************************************************************************/
class Foo {
...
};
/* CORRECT: */
//////////////////////////////////////////////////////////////////////////////
// class Foo performs the following
// ...
//
class Foo {
...
};
Comments in the second category are typically low-level, algorithmic details. They should be placed as
close to the pertaining code as possible, preferably in the same line. Although close to the code, the
comments should be visually separated from code as much as possible by right-justifying them. Following
section gives examples of aligning such comments:
Copyright Quantum Leaps, LLC. All Rights Reserved.
6 of 18
Quantum Leaps
C/C++ Coding Standard
References and notes should be attached in form of the "notes" comment at the end of the module as
shown in the next section describing the module layout.
Write comments in clear English. Use simple sentences: noun, verb, object. Use active voice. Be
complete. Good comments capture everything important about the problem at hand. Ideally, it should be
possible to get a sense of the systems operation by reading only the comments.
For portability, never use C++ comments (//) in C, although many C compilers recognize C++ comments.
(But the point is that some dont!). Conversely, avoid using C comments (/*..*/) in C++.
3.4
Module Layout
The module is organized as follows:
#include statements
Implementation
Notes
/* Real-Time Kernel */
/* embedded-systems-friendly assertions */
7 of 18
Quantum Leaps
C/C++ Coding Standard
8 of 18
Quantum Leaps
C/C++ Coding Standard
result *= base;
}
base *= base;
}
return result;
9 of 18
Quantum Leaps
C/C++ Coding Standard
signed
unsigned
8 bits
int8_t
uint8_t
16 bits
int16_t
uint16_t
32 bits
int32_t
uint32_t
The main goal of the <stdint.h> indirection layer is promotion of code portability across different
platforms. To achieve this goal the C99-style types listed above should be consistently used instead of
the "raw" C/C++ types, such as long or unsigned char, and inventing different aliases for the C/C++
types is forbidden.
10 of 18
Quantum Leaps
C/C++ Coding Standard
Names
5.1
Reserved Names
The ANSI C specification restricts the use of names that begin with an underscore and either an
uppercase letter or another underscore (regular expression: _[A-Z_][0-9A-Za-z_]). Much compiler runtime
code also starts with leading underscores.
These names are also reserved by ANSI for its future expansion:
Regular expression
purpose
E[0-9A-Z][0-9A-Za-z]*
errno values
is[a-z][0-9A-Za-z]*
Character classification
to[a-z][0-9A-Za-z]*
Character manipulation
LC_[0-9A-Za-z_]*
Locale
SIG[_A-Z][0-9A-Za-z_]*
Signals
str[a-z][0-9A-Za-z_]*
String manipulation
mem[a-z][0-9A-Za-z_]*
Memory manipulation
wcs[a-z][0-9A-Za-z_]*
To improve portability and avoid name conflicts, never use a name with a leading underscore or one of
the name patterns reserved for future expansion.
5.2
Naming Conventions
This section does not intend to impose strict "Hungarian-type" notation. However, the following simple
rules in naming various identifiers are strongly recommended:
No identifier should be longer than 31 characters (this is a stricter version of MISRA-C rule 11).
Type names (typedef, sturct and class) should start with an upper-case letter e.g., struct Foo.
Optionally, the type name can be prefixed with the module identifier, e.g., typedef uint16_t QSignal,
class QActive.
Ordinary C functions and C++ class member functions start with a lower-case letter.
Member functions of classes coded in C (see Section 6) are prefixed with the class name and an
underscore, so per the previous rule must begin with an upper-case letter. (QActive_start()). Besides
clearly distinguishing the member functions, this rule minimizes link-time name conflicts with other
functions (including third-party library functions).
Global functions are prefixed with a module name and an underscore (e.g., QF_start()). Package-scope
functions, visible only from a closely related group of source filesthe package, are additionally suffixed
with an underscore (QF_add_()). Besides clearly distinguishing global and package-scope functions, this
rule minimizes link-time name conflicts with other functions (including third-party library functions).
Global variables should be prefixed with the module name and an underscore (e.g., QK_readySet).
11 of 18
Quantum Leaps
C/C++ Coding Standard
Local variables (visible within one module only) should start with l_, e.g., l_bitmask. All local
variables should be declared static at the file scope (MISRA-C rule 23).
C++ class attributes (data members) should should start with m_, e.g. int8_t m_foo. This
convention allows easy distinction between the class data members and other variables like, for example,
member function arguments.
Constants (numeric macros or enumerations) should be in upper-case with underscores "_" between
each word or abbreviation (FOO_BAR). Global constants should be prefixed with the module name/identifier
(Q_USER_SIG).
All other parts of identifiers composed form multiple words should be constructed with capitalizing letters
at word boundaries like: fooBarTar, and not foo_bar_tar.
Generally, the more broad the scope the more descriptive the name should be. For a very limited scope, it
is recommended to use single letter identifiers. For example:
o
12 of 18
Quantum Leaps
C/C++ Coding Standard
6.1
Encapsulation
Encapsulation is the ability to package data with functions into classes. This concept should actually
come as very familiar to any C programmer because its quite often used even in the traditional C. For
example, in the Standard C runtime library, the family of functions that includes fopen(), fclose(),
fread(), and fwrite() operates on objects of type FILE. The FILE structure is thus encapsulated
because client programmers have no need to access the internal attributes of the FILE struct and
instead the whole interface to files consists only of the aforementioned functions. You can think of the
FILE structure and the associated C-functions that operate on it as the FILE class. The following bullet
items summarize how the C runtime library implements the FILE "class":
Attributes of the class are defined with a C struct (the FILE struct).
Methods of the class are defined as C functions. Each function takes a pointer to the attribute
structure (FILE *) as an argument. Class methods typically follow a common naming convention
(e.g., all FILE class methods start with prefix f).
Special methods initialize and clean up the attribute structure (fopen() and fclose()). These
methods play the roles of class constructor and destructor, respectively.
This is exactly how QP/C and QP-nano frameworks implement classes. For instance, the following
snippet of QP/C code declares the QActive (active object) "class". Please note that all class methods
start with the class prefix ("QActive" in this case) and all take a pointer to the attribute structure as the
first argument "me":
typedef struct QActiveTag {
QHsm super;
. . .
uint8_t prio;
} QActive;
/* public methods */
int QActive_start(QActive *me, uint8_t prio,
QEvent *qSto[], uint16_t qLen,
void *stkSto, uint32_t stkSize,
QEvent const *ie);
void QActive_postFIFO(QActive *me, QEvent const *e);
void QActive_postLIFO(QActive *me, QEvent const *e);
/* protected methods ...*/
void QActive_ctor(QActive *me, QPseudoState initial);
Copyright Quantum Leaps, LLC. All Rights Reserved.
13 of 18
Quantum Leaps
C/C++ Coding Standard
6.2
Inheritance
Inheritance is the ability to define new classes based on existing classes in order to reuse and organize
code. QP/C and QP-nano implement single inheritance by literally embedding the parent class attribute
structure as the first member of the child class structure. As shown in the following figure, this
arrangement lets you treat any pointer to the Child class as a pointer to the Parent:
(a)
Parent
Child
(b)
(c)
me
Attributes
inherited from
Parent
Attributes
added by
Child
In particular, such memory alignment of the Child attributes with the Parent attributes allows you to
always pass a pointer to the Child class to a C function that expects a pointer to the Parent class. (To be
strictly correct in C, you should explicitly upcast this pointer.) Therefore, all methods designed for the
Parent class are automatically available to Child classes; that is, they are inherited.
For example, in the code snippet from the previous section class QActive inherits from class QHsm.
Please note the first protected attribute "super" of type QHsm in the QActive struct definition.
14 of 18
Quantum Leaps
C/C++ Coding Standard
Design by Contract
Design by Contract is a very powerful set of techniques introduced by Bertrand Meyer [Meyer 97]. The
techniques are based on the concept of contract that formally captures assumptions and delicate
dependencies between software components. The central idea is to enforce fulfillment of these contracts
by instrumenting code and explicit checking against contract violations. Contracts may be in form of
preconditions, postconditions and invariants. In C/C++ they are implemented in form of assertions. Some
of the listed benefits of Design by Contract include [Samek 03]:
An effective framework for debugging, testing and, more generally, Software Quality Assurance
(SQA)
A technique for dealing with abnormal cases, leading to a sage and effective language constructs
for exception handling.
In deeply embedded systems, assertion failure must be treated differently than on desktop computers.
Typically, standard actions of printing out assertion failure statement and exit are not the right approach.
For that reason a customized behavior in case of contract violation is coded in "qassert.h" include file [QL
04]. This header file defines the following assertions:
Q_ASSERT()
General-purpose assertions
Q_ALLEGE()
Q_REQUIRE()
Q_ENSURE()
Q_INVARIANT()
Q_ERROR()
Q_ASSERT_COMPILE()
Compile-time assertions
15 of 18
Quantum Leaps
C/C++ Coding Standard
16 of 18
Quantum Leaps
C/C++ Coding Standard
Location
[C99]
[Humphrey 95]
[Labrosse 00]
[Meyer 97]
[MISRA 98,04,12]
[Samek 97]
[Samek 02]
[Samek 03]
[Stroustrup 10]
[QL]
www.quantum-leaps.com
www.state-machine.com
17 of 18
Quantum Leaps
C/C++ Coding Standard
10 Contact Information
Quantum Leaps, LLC
103 Cobble Ridge Drive
Chapel Hill, NC 27516
USA
+1 866 450 LEAP (toll free, USA only)
+1 919 869-2998 (FAX)
e-mail: [email protected]
WEB : http://www.state-machine.com
http://www.quantum-leaps.com
Practical UML
Statecharts in C/C++,
Second Edition
(PSiCC2),
by Miro Samek,
Newnes, 2008,
ISBN 0750687061
18 of 18