Layout
General Regulations
Expressions
Control Structures
Record Type
Class
Prechecked Loop
Postchecked Loop
Counting Loop
Binary Selection
Selection
Functions
Function Declaration
Function Definition
Function Call
Types And Instances
Modules
Comments
General Regulations
- Each line of code contains one expression at most.
- Lines should not exceed a length of 80 characters.
Expressions may be wrapped to multiple lines, if necessary. The succeeding
lines are indented by one level.
nCounter =
10 * StartOfRange() * OFFSET - SafeDistance();
- The tab width is 4 characters. The tab
width is to declare in the file header.
- The indentation width is one tab (4
characters respectively, if different from tab width).
- A comma or semicolon is never preceeded by a whitespace (blank, tab,
newline).
- A comma or semicolon is always followed by a whitespace (blank, tab,
newline).
- Single source files exceed the length of 1,500
lines only by way of exception.
- Comment templates are used for
file and function
headers.
Expressions
- If an expression
in brackets has to be splitted to more than one line, (e.g. a long if-condition
or a function's parameter list), the outer brackets are placed in the same
column and are indented by one level to avoid confusion with curly braces.
The expression itself is indented by an additional level.
if
(
((MIN_RANGE < nCounter)
&& (MAX_RANGE > nCounter)) ||
(0 == nCounter)
)
{
Expressions();
}
memcpy
(
pDestination,
pSource,
lSize
);
- Operators are enclosed within
whitespace characters.
Exception: the operators dereferenciation and Address
are placed directly at the name they are applied to, without any whitespace.
If they are applied to an expression, the expression must be enclosed by
parentheses.
|
C/C++
|
Pascal/Delphi
|
int i = 27 * *pSum;
y = f(17 + &x);
float x = *(pBuffer->m_pData); |
i := 27 * pSum^;
y := f(17 + @x);
x := (pBuffer^.m_pData)^; |
- In a pointer or
reference declaration the operator is written directly to the type. A typedef
declaration is preferred.
double* pSum;
float Function(const CComplex& anApproach);
better:
|
C/C++
|
Pascal/Delphi
|
typedef double* PDOUBLE;
PDOUBLE pMean, pVariance; |
type PDOUBLE = ^double;
var pMean, pVariance: PDOUBLE; |
- Parentheses are neither preceeded nor followed by whitespaces, except
parentheses led or followed by an operator or key word respectively.
f(c), Pi() + 13, if (bCondition),
but not:
f (c), f( c ), Pi()+13
- In a comparison the constant should be placed
left to the operator to avoid an accidental assignment.
if (NULL == pDataBuffer)
{
return;
}
- Type casts have always the form
LONG(nNumber) * Size(); // C++
or
(LONG)(nNumber) * Size(); /* C */
and not
(LONG) nNumber * Size();
to make the cast's range clear.
- (C, C++) The ? operator is to use sparingly. In doubt,
prefer an if-else construct. A ? expression must not
be split to multiple lines (in this case an if-else construct
is mandatory). If a component of an ?: expression is an expression
itself, it must be enclosed within brackets.
nLength = (NULL != p) ? ::strlen(p) : 0;
// ::strlen() parameter must not be NULL.
Control Structures
- The block-enclosing curly braces
have the same indentation level as the statements before and after the
block.
|
C/C++
|
Pascal/Delphi
|
| Statements();
for (i = 0; LIMIT > i; ++i)
{
Statements();
}
Statements();
|
Statements;
for i := 0 to Pred(LIMIT) do
begin
Statements;
end {for};
Statements;
|
- Before (key word) and after (closing brace) a control structure an
empty line is inserted (optional before an else), except there
is only an opening brace in the preceeding line. Control structures are
formmatted as follows:
|
control structure
|
C/C++
|
Pascal/Delphi
|
record
|
typedef struct
{
float m_fReal;
float m_fImag;
} CComplex; |
type CComplex =
record
m_fReal: single;
m_fImag: single;
end {record}; |
class
|
class C : CSuperclass
{
public:
C(void);
private:
int m_nSize;
};
|
type C =
class (CSuperclass)
public
constructor Create;
private
m_nSize: integer;
end {class};
|
prechecked loop
|
while (bExpression)
{
Statements();
} |
while (bExpression) do
begin
Statements;
end {while}; |
postchecked loop
|
do
{
Statements();
} while (bExpression); |
repeat
Statements;
until (not bExpression); |
counting loop
|
for (i = 0; i < MAXIMUM; ++i)
{
Statements();
} |
for i := 0 to Pred(MAXIMUM) do
begin
Statements;
end {for}; |
binary selection
|
if (bExpression)
{
Statements();
}
else if (bExpression)
{
Statements();
}
else
{
Statements();
}
|
if (bExpression) then
begin
Statements;
end
else if (bExpression) then
begin
Statements;
end
else
begin
Statements;
end {if};
|
selection
|
switch (nChoice)
{
case 1:
{
Statements();
break;
}
default:
{
Statements();
break;
}
}
|
case (nChoice) of
1:
begin
Statements;
end;
else
begin
Statements;
end;
end {case};
|
(C, C++) Case labels in a switch statement
may be combined (i.e. there is no code between two case labels). This is
to point out in a comment before the label group. If the break
statement is missing between two case labels (i.e. there is code between
the labels), an ample comment has to point out this situation and must
mention the following label!
switch (nNumber)
{
case 1:
{
int n = 0;
Statements();
break;
}
// case group: explanation of the common
characteristics
case 2:
case 3:
case 4:
{
Statements();
break;
}
case 5:
{
Statements();
//-- No break; continue
with 6 --//
}
case 6:
{
Statements();
break;
}
}
(C) Switch statements may be formatted by indenting the case labels
half a level, if, for effinciency purposes, function calls would be too
expensive and several control structures have therefore to be nested.
switch (nChoice)
{
case 1:
{
Statements();
break;
}
default:
{
Statements();
break;
}
}
- The block of a control structure must always be enclosed within braces
(except cases within a switch statement), even if it
is empty.
while (!DidTimerExpire())
{
}
- A control structure's condition is never placed on the same line with
its statement.
|
while (bCondition)
{
Statements();
}
while (Condition())
{
}
|
| Inadmissible: |
while (bCondition) Statement();
while (bCondition); |
Functions
Function Declaration
- In a function declaration the parameters are either declared in a single
line or each parameter is declared on a seperate line. (C) Function declarations
using K&R syntax are forbidden.
|
C/C++
|
| int Sum(const int n1, const int n2, float f);
void PushCommand
(
PStack pCommandStack,
const CCommand aCommand
);
|
|
Pascal/Delphi
|
| function Sum(const n1, n2: integer; f: single): integer;
procedure PushCommand
(
pCommandStack: PStack;
const aCommand: CBefehl
);
|
- Each function is declared and commented on a seperate line. Different
functions may be described in a single comment, if they differ only in
their parameter lists and have the same responsibilities and functionalities.
- (C, C++) If a function has no parameters, the key word void
must be used.
void WasteTime(void);
Function Definition
- When defining a function, each parameter is to write into a single
line. Parameters must be commented. (C++) Default parameters are listed
(and commented out).
|
C/C++
|
Pascal/Delphi
|
void PushCommand
// comments
(
PStack pCommandStack,
//
list of executed commands
const CCommand aCommand
//
command to store
)
{
Statements();
}
int SystemState
// comments
(
const BOOL bErrorsOnly
/* = TRUE */
//
only errors are reported
)
{
Statements();
}
|
procedure PushCommand
// comments
(
PStack pCommandStack,
//
list of executed commands
const CCommand aCommand
//
command to store
)
{
Statements;
} |
- (C++) Initializers for data elements in a constructor are written in
seperate lines.
CComplex::CComplex
// comments
(void)
: m_dfReal(0.0),
m_dfImag(0.0)
{
}
Function Call
- If possible, alle parameters in a function call are written into the
same line.
- (C++) If a non-member function is called, it is preceeded by its scope.
|
C++
|
Pascal/Delphi
|
if (0 < Std::strlen(lpszName))
{
Std::printf("Hello %s.", lpszName);
} |
if (0 < System.Length(sName))
begin
System.Write('Hallo ', sName, '.');
end {if}; |
Types And Instances
- Each public variable is declared and commented in a seperate statement.
int msg_nTotalNumberOfErrors = 0; // Number of
all errors that occurred.
int msg_nPreviousNumberOfErrors = 0; // Number of errors that occurred
since
//
previous call.
Inadmissable:
int msg_nTotalNumberOfErrors = 0, msg_nPreviousNumberOfErrors =
0;
// Total and previous number of errors occurred.
- Each data element is declared and commented in a seperate statement.
Inadmissable:
private:
CKlasse m_a, m_b, m_c;
- (C++) The declaration sections
within classes are ordered as published – public – protected
– private. Within each section new definitions and types are followed
by function elements and data elements are declared at the end of each
section.
(C++/Delphi) Exception: Properties may be declared after any other
declaration, since properties may access private data elements.
class CLineStyle
{
public:
//-- constructors --//
CLineStyle
(
const int nLineStyle = SOLID_LINE,
const int nLinienWidth = NORM_WIDTH,
const unsigned uLinePattern = 0
);
//-- selectors --//
int LineStyle(void) const;
int LineWidth(void) const;
unsigned LinePattern(void) const;
//-- modifiers --//
void UseLineStyle(const int nLineStyle);
void UseLineWidth(const int nLineWidth);
void UseLinePattern(const unsigned uLinePattern);
protected:
//-- agents --//
virtual void Print(void);
virtual void Draw(void);
private:
//-- Datenelemente --//
int nLineStyle;
unsigned m_uLinePattern;
int m_nLineWidth;
};
- (C++) Function declarations are grouped thematically. The groups are
seperated by comments. Within these groups the polymorphic functions preceed
the non-polymorphics. The Selectors should preceed the modifiers. The ordering
of the topic groups is identical in each access section (public,
protected, private, published).
- (Pascal/Delphi) Though the names of simple types (integer, double,
etc.) are no key words in Pascal, they are written in lower case, so the
notation is consistent to C/C++. Also, a confusing situation can be avoided:
Inadmissable and confusing:
|
var u: Cardinal;
var n: Integer;
var x: Double;
n := Integer(u); // Attention: A type cast here…
u := Trunc(x); // …but a function call
this time!
|
|
|
n := integer(u); // type cast
u := Trunc(x); // function call |
Modules
- (C/C++) The declaration file contains
constant definitions, type definitions and function prototypes accessible
to other modules. To avoid multiple #including, this file is framed
by the following construct, :
#ifndef _FILENAME_H
#define _FILENAME_H
...
#endif
- (C/C++) In the implementation file
the declaration file is loaded (if necessary with other declaration files)
by #include eingeladen. The functions declared in the declaration
file are defined here. Private variables and functions are declared static.
- Modules may go without function definitions. If types and constants
are defined only, the implementation file is dropped.
- (C, C++) It is forbidden to #include implementation files
(.C bzw. .CPP).
(C++) If template classes are implemented, the function definitions
may be written into a seperate file. It has the extension .h.
- The correctness of modules is checked (supportingly) by the compiler.
At the maximum warning level no messages must be generated.
- (C) If possible, and not supported by the compiler, a check has to
be done by the lint tool.
[back] | [next]
| [TOC] | [Introduction]
| [Programming Style Guide] | [Annexes]
Copyright © 1997-1998 by Uwe Sauerland