Use template.c
for C files.
C++ files have the suffix .cpp, header files have the suffix
.h, implemented templates have the suffix .hh.

Every file in the project must have a unique name.

Only a few classes per file.
If there is more than one class in a file then they should have to do with each other
or be part of a common package (e.g. small helper-classes that would otherwise be implemented as a class in a class).

Brackets are aligned vertically. For example:

int myFunction( .. )
{
if ( .. )
{
for ( .. )
{
..
}
}
else
{
..
}
}

The indentation is 4 spaces per level!
K&R-Style is prohibited!
Structure Files by using spaces.
More about indentation and spaces.

Larger coherent parts of the code (or the header) should be separated by a blank line (like a paragraph).

Always initialize in the constructor.
Use initialization instead of allocation in the constructor (whenever possible).
Reason: performance.

Always call the constructor of the base-class if you are in the constructor
(in the initialization-list of course).

You should always declare a copy-constructor and an assignment-constructor.
If the class doesn't need them, make them private
(Reason).
Implement the copy-constructor / the conversion-constructor like this:

A::A( const A/B &source )
{
*this = source;
}

Constructors with only one parameter (called conversion-constructor)
must be made explicit (Reason).
Except the copy-constructor! (Reason: return-by-value and pass-by-value
will cease working; the compiler may optimize the copy away, and usually does so,
but the standard calles for it -- probably, to make the program work on compilers
that don't support that optimization.)
The same is true for constructors, where all but one argument have default values.

If class A is used only by pointer or reference in the header file of class B,
then use a forward declaration; do not include the header-file of class B. Example:

class A;
class B
{
private:
class A *a;
}

Do not change an operators "meaning" and pay attention to it's semantic counterpart.
(Example)

If possible, implement binary operands globally (not as instance methods).
(Reason: see "Effective C++", Item 19.
In the end it comes down to this: if it's not absolutely necessary to be in the class,
then define a method outside of the class, thus as a global method.
Scott Meyer about this: "I've been battling programmers who've taken to heart the
lesson that being object-oriented means putting functions inside the
classes containing the data on which the functions operate. After all, they
tell me, that's what encapsulation is all about.
They are mistaken."
Here you can find a detailed explanation of Scott Meyers
(source) ).

Reference parameters are always declared as const, otherwise
as a pointer (i.e., they can be altered)
(Reason).

Use namespaces.
Never write using namespacemy_package;
in a header-file!

If methods have to be overloaded, they also have to be virtual.
(ARVIKA 15.1 -- does someone know why?)
Virtual methods must also be declared as virtual
in subclasses (if they are overloaded)
(Reason).

Never overwrite an inherited default parameter.

Private methods can not be made public in a subclass.

Avoid casts.
If you do have to use them, then use the new C++-Casts
(Reason and Example).

Be careful with the definition of cast-operators!
Here too can happen unwanted things unnoticed.
(Example)

Write const-correct code.
(This takes effort in the beginning ;-) )
Write your code const-correct right from the start!
(It is practically impossible to do it later on.)
And don't forget the const at the "right" side of a function.

Use unsigned int, if you don't need the negative values.
This is usually the case in loops. You should think about this
for every prototype that gets int.
Activate the warnings for this (-Wsign-compare in gcc).

Don't count on the order in which global or static member
are initialized!
(The standard defines this order for a translation-unit,
but you just have to switch the order of two definitions and might break!)

One function, one task!
Bad examples: Stack::Pop()
and e.g. EvaluateSalaryAndReturnName().
(Reason: well arranged, easy to make exception-safe.)

Code-Example

For those in a hurry we have an
example
with annotated code, that contains some of these guidelines.

Part 2 - For Non-Experts

These guidelines and tips are meant for all those who are relatively new
in the department and do not yet have decades of coding experience in C/C++
(i.e. student assistants and graduate students)

These guidelines should help you to develop a good programming style.
I also put some general programming tips together that (hopefully)
help you to complete your program faster, to produce less bugs and
to find bugs faster.

Now I hear some of you groaning:
"Now I can't even program the way I want!",
and: "Do I really have to read through all this?".
I thought the same when I'd been given guidelines for the first time.

From my years of experience I can assure you that:
yes, it has to be if you are working in a team.
And even if you are not working in a team, some basic rules
and a good programming style are useful because they help you.
In any case you'll get on your colleagues bad side
if you have a bad style! :-)

All in all I tried to have as few rules and restrictions in the
guidelines as possible and only as much as necessary:
obviously there are several good programming styles1),
and everyone should and must develop his own style.
But it is also obvious that there are much more bad than good styles
...

1)
Mathematically speaking: on the set of programming styles,
there is only a partial order, not a total one :)

Generally speaking, these guidelines may be broken if (and only if)
the source code becomes more readable, more robust, or better to maintain.

By the way, it goes without saying that you wont write perfect code
just after reading these guidelines. No master has yet fallen from the sky.
As with man-pages you have to look in to the guidelines every once in a while.
Even I am still working on my style :) .

These guidelines can only give the roughest advice; the subtleties
are too many and too individually to be listed in a guideline.
It is better if you run a "style-daemon" in your head that checks your
style while you areprogramming and that constantly expands it's database.
;-) .

The second half of these guidelines contains some tips and tricks for Unix, C
and other stuff that you need in daily life as a programmer or that you can make use of.

Good points, bad points

This section is from
"C++ Coding Standard",
but I simply copy it here because it summarizes quite well what guidelines are good for:

Good Points

When a project tries to adhere to common standards a few
good things happen:

programmers can go into any code and figure out what's going on

new people can get up to speed quickly

people new to C++ are spared the need to develop a personal
style and defend it to the death

people new to C++ are spared making the same mistakes over
and over again

people make fewer mistakes in consistent environments

programmers have a common enemy :-)

Bad Points

Now the bad:

the standard is usually stupid because it was made by someone
who doesn't understand C++

Syntactic and "semantic" practices are a part of this. I claim that
it is not possible to write good code without a good coding-style
(in terms of robustness, maintainability, efficiency, elegance).
I also claim that one can only program efficiently in the long term
with a good programming style!
(Because: bad style -> more bugs or bad design -> longer bug search
or more redesigns -> more time in total.)

It may seem absurd or annoying to some of you that we set such high
value to namesa).
But the naming of variables, functions, methods and classes is actually
the most important criterion for a good programmer (and a good design)!
This is even more important in object-oriented-programming than in pure C.
Bad naming can make a library almost unusable.

a)
And yet Goethe said: "Name is but sound and smoke.".
(Martha's Garden)

When choosing a name for a class, an object, a variable or a type
you should think about what another programmer, who sees your code
for the first time and knows nothing about it, can discern from that name.
It is best if he can get the meaning from the name.
Longer names are usually better for the understanding then short ones
(but they can annoy the users of your code if they are too long :))
For example ParameterUnavailException is much more understandable
than parmunavlex.

Names are a good indication of a flawed object-oriented design:
if they get too long, make no sense from a global perspective or
if every function is called doIt, make and thing
then it's hight time to check the design!
If class names consist of more than 3 words, then that is a sign that
you are mixing up several entities of your system.

The terms member function etc. that Stroustrup introduced are preposterous!
They are called "class methods" (static member functions)
and "instance methods" (non-static member functions).
Analogue for variables.

Functions/methods usually do something, so their names
should be composed of a verb + noun (inCaps-notation).
Here is an example of our convention:
calcDistance.
(Other conventions are: SetParam, or create_stripe.
I personally think the underscore-notation is not so nice.)

If a function returns a property,
then it is better to compose the name of "is" or "has"
+ adjective; e.g. isFlat
or hasColor.

If several methods/functions in the same module/class have similar
parameters with similar meaning then these names should have
the same (or at least a similar) name.
This is especially true for overloaded functions.

Names that are used for conditional compiling should be "all caps"
(e.g. #ifdef DEBUG_ON).

The names of enum-types should indicate that it is such a type.
They should therefore end with an E, e.g.: renVisibilityE.
The names of the "members" of an enum are composed like a define:

Struct-, union- or pointer-types do not need
a labelling because the type is clear from the context.
If you want to you can consider suffixes analogue to the enum-convention.
Some possibilities are:
renViewpointS, or renViewpoint_s
for struct-Types;
objPolyhedronP for pointer.
Other conventions are possible; I think the convention "cap-suffix"
is the best (and the fastest to type :)).

Furthermore I'd like it if you could think of conventions that
show the semantic meaning of a variable/object in it's name;
e.g. begin all vectors with a v, end all matrix-names with
mat, begin all exception-objects with ex, etc.

It is the same as above for C++;
although functions must have a prefix (2-4 letters) which
represents the module in which they are defined:
prefix + verb + noun.
E.g.:
plhCalcDistance,
INTOsetButtonParam, or pf_create_stripe.
The same is true for functions that return a property:
prefix + "Is" + adjective; e.g. plhIsFlat.

Classes use the same naming conventions as functions with the exception that
class names begin with a capital letter. It is not necessary to add a
capital C as an additional prefix or suffix to class names (redundant).
Class-variables/-functions and instance-variables/-functions are composed
with the same naming conventions.

Functions that are used to set instance-variables should begin with set.
Functions that return the value of an instance-variable should have the same name
as the instance-variable (or begin with get).
The variable itself begins with an underscore.

If several classes together form a library, then it can be very useful
if the class names have a prefix (e.g. pf for Performer).
It is not necessary to add the prefix to the function or variable-names
of those classes.
The files of a class have the same name as the class (e.g. the file
matrix.cc contains the class libMatrix).

All functions begin with a lower-case letter. If it is not too much of a change
for you than use the inCapsNotation
(i.e. getBla or setNewWonderfulBlub).

Avoid redundancy in the names. In the following line:

myWindow->setWindowVisibility( libWindow::WINDOW_VISIBLE);

we had to type 4× "window" and 2× "visible".
This is just as good and understandable:

myWindow->setVisibility( true );

(Everyone knows that you can only pass boolean values because of the name.
Therefore 1 is ok as a parameter in this case.)

The Enum-Problem in C++

In C, it was easy to use enums where several options are ORed
and passed as a parameter.
E.g.:

Generally speaking, as little comments as possible, as much comments as necessary.

On the one hand comments do help to organize your thoughts (and therefore to
program better); on the other hand it helps you if you have to change something
in the code after a year (or if someone else has to do it) ---
don't tell me that you can remember all of it, or that everything is self explanatory!
:) .

There are four types of comments:

An overview of the "big picture" at the beginning of a class,
the functions of the file (the class), used "compile flags"
(conditional compilation via ifdef).

Before each function a description what it does,
it's in- and output-parameters, pre- and post-conditions,
side-effects, caveats, bugs, etc.
(see the assert-macro
for pre- and post-conditions)

In the code itself for larger blocks of lines.

For variables (all global or class variables and some local),
members of struct-typedefs and the like.

Comments should have a consistent form in the entire module (see the commentary-template).
Comments for functions should be made with the block from the template,
so that they can be extracted by an automated tool.
You can write comments in German or English, whatever you are more comfortable with.

The comment must make the meaning of the parameters clear, what class-variables
(or static variables) are used (as few as possible), what is returned,
the conditions that must be met by the caller.
A description of the function has to be included of course.

If some parameters are return-parameters, then this has to be made clear
without ambiguity! (Width in the example.)

Here is an example for the comments of a function:

/** Do something (single line)
*
* @param param1 blubber (in)
* @param param2 bla (out)
*
* @return
* Description of the return values, e.g.
* -1 if it failed, 0 if it's ok.
*
* Detailed, multi-line description, e.g.
* This function calculates ...
* Based on the algorithm of ...
*
* @throw Exception
* Detailed description of the exceptions and their conditions, e.g.
* XOutOfMemory, if no more memory is available.
* XCoffee, if the coffee is gone.
*
* @warning
* Description of input parameter values or conditions,
* that cause errors or crashes which are not intercepted.
* (Should only occur very rarely!)
*
* @pre
* Detailed description of the preconditions, e.g.
* It is expected that the init() function has been called.
* Param1 has to be calculated by the function blub().
*
* @sideeffects
* Side effects, global variables that are modified, .., e.g.
* @arg The global variable @c M_Interest will be modified.
*
* @todo
* Make faster.
*
* @bug
* Produces a core dump, if it is @a param1 = 0.0 .
*
* @internal
*
* @see
* Cross-references to other functions, e.g., because they calculate something similar,
* or because there is any relationship between the two. Example:
* anotherFunction()
*
**/

In my experience, it's fastest if you write the comment to a function
when it is "half" done, because then everything is still fresh.
Once it is completely finished, you should look over it again,
and see if the comment is still correct.

Sometimes it is helpful if you write the comment partially
even before you start coding!
E.g. a few lines about what the function should do, and a list of
parameters can help a lot to order ones thoughts.

He who writes a complete module without any comments ---
"I write the comment once everything is finished" ---,
will never write the comment at all. (Because it is just too much
at once, and because the subtleties like caveats are no longer in memory.)

It is important that you get an overview of the function and its "workings"
by skimming through the comments in its body. An in-line comment should only
tell what happens in the code block, not how it happens
(e.g.: "calculate mean" is better than "sum up and divide by n").

If there are important conditions that must be met, or loop invariants,
then it makes sense to record them in a comment so that are not violated
by mistake if you (or maybe someone else!) is modifying the code later on.
One example is at the top, here is another one:

A template for C and C++ files can be found in the CVS in
internal/Templates/class.{cpp,h}.
(Replace CLASSNAME with the name of the class, or, better yet,
let the editor do it while generating the files.)

The .cpp-files do not contain any CVS-keywords except an id-keyword.
This is meant for the product version and will only be expanded for that version
(to identify the separate versions of which the system is made up of).

That means, that everyone has to put the following lines in their
~/.cvsrc:

Classes have several sections, analogous to C files, which should be ordered as following:

public constants, public types

public variables (if permitted)

public functions

protected stuff (same order)

private "parts" :-) (same order)

Header-Files

The structure of header files is similar to that of C-files.

The "content" of header files has to be protected against multiple inclusion
with ifndef like it has already been done in the
template.h.
(The pragma-line does the same as the ifndef-brace
and is more efficient at compilation but it is note available on all platforms.)

The name of a header-file is the same as the corresponding C-file
(i.e. Foo.h and Foo.cpp).
One should avoid names that are already assigned in /usr/include
for standard header files such as math.h or gl.h).

Pure C

Only that, what a user of the lib or
the object-file really has to know belongs in a header file -- everything else goes in the
corresponding C-files or in "internal" header files which do not get
included in the "user-header-file". (This can be non-trivial for big projects! :) )
Normal applications usually do not have extra header files!
This is not so easy/elegant in C++ because unfortunately you also have to
declare the private-methods in the header file.

Make C-header-files compatible with C and C++.
That means that you have to encase C-header-files with an extern "C" {}:

Maintenance in general consists of slight modifications to the source.
Those who make this maintenance, are almost never the ones
who originally wrote the code (for various reasons).
Even if the person who modifies the code is the original author:
if you're not constantly looking at the code for a year then
you're like to forget the details or even the "big picture".

This applies to modifications of the code by the author himself
a few months after the code has been created (best case),
as well as modifications 1-2 years later by someone
who has no idea of the "big picture" (worst case).

You can't establish many specific rules to make code easily maintainable --
you have to develop a sense of what constructs in the code are difficult to maintain.
Though you can heed the following general tips:

If a function can only be implemented through the public-interface of
a class than this function should not be a member function!
This increases the encapsulation.
(See [12])

With comments, you can give notes to others.

In the comment before the function:
"Assumptions" and "Caution".
These notes are filled out while writing the function/method!
Otherwise after only one week not even the author knows
what has to be considered when calling or even changing the function!

In-line-comment in the functions body for conditions,
e.g.: /* now nelems = 2 */:
or
/* MUST be done before ... because ... */
So in one year, if you have to change something, you still know
that this condition has to be valid in the entire function.
It it also for your own control to see if you considered
whether this condition exists for the rest of the function!
(Who remembers wp- or Hoare logic?)

If a particular section of code is very sensitive to changes
you should comment that.
If making changes in a piece of code make changes in another
piece of code necessary you should comment that (in the former!).

This can be summed up very poorly. And if you have to change the code
blabla in one year it is easy to forget one of the two branches!
And then you'll be searching a bug for hours if you're lucky and it'll
occur right away and not after 2 month when you've forgotten that
you changed anything at all...

Avoid code that can be "misunderstood" later on; e.g.
assignments in conditions:

if ( a = b )

this will definitely be "repaired" by someone who is searching a bug in the function so that it will look like this

if ( a == b )

Or: does this code really mean

for ( c = s; c < ...; ... )
c = f(...);

a for-loop without a body (in that case the semicolon got neglected) or is it just badly indented?
But if you write

The primary objective in this context is the good readability of the
source code for others! (Especially for me.) He who programmes
with the motto, "it was hard to code, so it should be hard to read",
is just acting uncooperatively.

To achieve good readability you also need a good structure of the entire file,
(see Structure and File-Layout), reasonable
modularisation, structure in single lines, and also comments
(see Commentaries)

All bugs listed here did actually happen!
Most of them took hours to locate.

Conclusion: if you think about your code for two minutes after
a programming session to see if you have covered all cases than
you can save hours of frustrating bug-searching later on!
"What happens if that pointer is NULL?",
"What happens if that string is longer than 100 characters after all
because e.g. a file-path is very long?",
"What happens if this number of ... is 0?",
"What happens if the graphical object changes? If it moves?
If it changes its form? Or its colour?,
"What happens if the object does not reside at the root of the scene graph?".

I even know of cases of extremely bad code (bugs, bad modularity,
horrible modifiability, etc.) that took three people each(!) one week
to maintain, adjust and debug. The code was (unfortunately) hacked/copied
together in just one week. -- If one had invested one more week to implement
it correctly than a total of two man-weeks could have been saved.

Inheritance

Before you declare one class B as a subclass of A, you should
ask yourself if they really have the relation "B is an A"
or rather the relation

"B uses A" or
"A is part of B".
In this case one of the two classes simply contains a
pointer to an instance of the other. There is no inheritance
between the two classes.

"B is like an A" exists.
In this case both classes are subclasses of a common superclass.
You may have to define a new superclass and move a lot of code
from class A to that class.

Especially multiple inheritance is often mistakenly used when an
object actually contains pointers to several other objects
(multiple "uses" relationship)!

Constructors and Destructors

Always write a virtual destructor, even if the class does not need one!
(Problem: delete on pointer to baseclass.)
The only exception are very small classes(in terms of memory),
and when the extra memory for the vtable is unacceptable.
In such a case it must be noted in the class comment!

If a class does not have/need a constructor than write a
default-constructor as private without an implementation
in the C-file (With the comment not implemented).
This prevents the compiler from creating one that might be faulty.
Always declare a copy-constructor and an allocation-operator. If the class
does not need them, make them private without an implementation.
The problem with C++ is, that you can't see from the code when the
copy-constructor and the assignment-operator are called.
See this example.

Constructors cannot return error codes.
There are two solutions for that:

Constructors may only contain code that is guaranteed not to fail.
Always use an init-function instead to do the "real"
initialization of an object (which may fail):

Always initialise all instance-variables in the constructor.
Do not use global variables n the constructor.

Do not call virtual methods in a constructor.

Use, if possible, initialisation instead of assignment.
By using assignments in the constructor many temporary instances might be created
- which leads to bad performance.
Basetypes (int, float, etc.) can be initialized
in the constructor via assignment.
Here is an expensive example with assignments:

Casts

static_cast<type>(expression)
instead of the old C-cast (type);
Reason: such a cast is easier to find with grep (and by "looking");
also the constness will not be changed.

dynamic_cast can be used to change a pointer to an object of the
base class to a pointer to an object of the subclass.
Actually the expression

dynamic_cast<type>( expression )

is a function that returns NULL, if expression
is not of the type type, but otherwise returns a pointer of the desired type.
Of course this only works if RTTI is supported and only if the
base class has a vtable (i.e. has one or more virtual methods)!

Exceptions

Pay attention to "exception-safety":
If an exception is thrown the object must still be consistent and may not leak resources
(like memory) and the program has to be in a "reasonable" state so that the execution can be continued.
That means that the programmer has to consider for every line of code that an exception can be thrown.

Do not throw exceptions in a destructor!!

Derive all exception-classes from std::exception (#include<stdexcept>).
It might make sense to use one of the subclasses of exception and derive from that
(logic_error, runtime_error, domain_error,
invalid_argument, length_error, out_of_range,
bad_cast, bad_typeid, range_error,
overflow_error, bad_alloc).

Catch by reference
(catch (XClass &x)), never catch by value
(catch (XClass x)).
(Reason: the exception that comes in might be a subclass.)
Or simply catch(XClass).

If possible make the try-block big.

C-style callbacks (e.g. callbacks to C-libraries)
should always be declared as "no-throw":

void myCallback( ) throw ()

Obey the idiom "Resource Allocation is Initialization".
Avoid new in the constructor or nest it in try
(because the destructor will not be called if an exception is thrown).
Maybe use auto_ptr from the stdlib
(they provide a simple mechanism to automatically free memory).
Maybe use "strong pointers" (see the
Official Resource
Management Page).

Always perform unmanaged resource acquisition in the
constructor body, never in initializer lists. In other words,
either use "resource acquisition is initialization" (thereby
avoiding unmanaged resources entirely) or else perform the
resource acquisition in the constructor body.
For example, say T was char and t_ was a
plain old char* that was new[]'d in the
initializer-list; then in the handler there would be no way to
delete[] it. The fix would be to instead either wrap the
dynamically allocated memory resource (e.g., change char*
to string) or new[] it in the constructor body where it
can be safely cleaned up using a local try-block or otherwise.

Do not use exceptions if it makes the code more complicated.
A normal return-code-scheme is probably better in that case.

Do not declare an exception-specification (throw( X, Y ));
document the potential exceptions in the functions comment instead.
Reason:

Short answer: even experts don't do it.
A bit longer answer:

Some compilers create very slow code if they encounter such an exception-specification;

If, however, an exception that is not in the specification arises than
unexpected() will be called -- this is often not what you want;

You can't write a meaningful specification for methods in templates anyway because
you know nothing about the future base type with which the template will be instantiated.

Methods, Functions and Operators

If a method is declared as virtual somewhere in the inheritance hierarchy
then it should be declared virtual in the entire hierarchy.
Therefore it is better documented that a method can be overloaded or rather that
the correspondent class in the superclass is actually virtual.
While the standard does say "once virtual, always virtual", it is "better to be explicit than implicit".

Virtual functions
(makes no sense, as these functions are bound at runtime.)

Functions with a variable number of parameters
(foo( int n, ... ))

A method, that should not change the instance by design, should be declared with const.
This prevents that code is inserted later on by mistake that changes something.
This is also the only kind of method that can be called for const-instances.

Warning: the default assignment-operator creates only a "shallow copy"!

The assignment-operator shall return void.
(Reason: something like if ( a = b ) can never happen then.)

Use operator-overloading seldom and consistently. An operator should always have
the same "meaning". (The is also true for function-overloading.)
Every user expects that, e.g. the ++-operator "increases" some internal state
and that the *-operator is an algorithmic multiplication.
Always implement the semantic opposite of an operator too.
If there is the operator == then everyone expects that there is also !=
and if there is ++ then -- should also be there
(sometimes this is not possible, e.g. an iterator over a singly-linked list).
If there is the operator < then there should also be >,
<= and >=. If there is +, then -,
+= and -= should also be there.
These "balanced" operators are good candidates for
factoring!

Never return a pointer to an instance-variable!
If it really has to be than only as a const pointer or reference!

Avoid call-by-value-passing of objects as arguments of a function.

Pointer or Reference?

The Problem: When looking at function-parameters that are declared as reference
you cannot see that they are not call-by-value5)!
If you want to use references as formal parameters in functions then only as const type &parameter!
Reason:
If you agree upon the convention that a pointer-parameter can be changed
and a reference-parameter cannot than you can just declare it const
so that the compiler also "knows" about this convention (and can therefore better optimize).

5)
In my humble opinion, references are not a good "improvement" in C++!

Another reason why references should always be declared as const
which should also convince pragmatics: temporary objects are const in principle.
So you cannot write something like this if a formal parameter is a not-const reference:

foo( A() );

Misc

Instance- or class-variables should never be public. Use get- and
set-functions instead. (Otherwise "data hiding" is compromised.)
(Exception: const public variables. These can only be set in the initialisation-list of the constructors.)

Offset pointer to members have to be justified very well! They usually are
a sign that something is wrong with the design (e.g. wrong identification of which objects
are best suited for the problem or wrong distribution of functionality).

Do not use temporary objects in function calls. Unless you really know when they will be deleted (do you know it?)

At system():
As I said earlier, there are always exceptions.
The system call is one of them ---
here you have to use hard-coded paths!
The problem: otherwise you depend on the users environment (PATH).

Example: you want to start a remote shell via system.
Wrong is:

system( "rsh machine ..." );

because the command rsh might not be in the users PATH,
and if it is, then the restricted-shell might be first in the PATH, and not the remote shell!

Therefore: always specify the full path of the command when using system (specify with #define at the beginning of the program). It's best to test beforehand with stat if the command really exists. So as an example:

Hard Array-Sizes

Consider:
"Hard" array-sizes have created many security-holes in Unix
(this is the class of "buffer overflow security leaks")!
(e.g. rsh
with 100k argument-string, or >1000 telnet connections per sec.)

Array-Indexing

In C the index of an array begins with 0!
It never begins with 1 (although it is done like that in Fortran).
If you do it anyway you will confuse everyone else and will definitely
produce an off-by-one bug directly or indirectly.

Thanks to the automatic inlining of modern compilers macros have become mostly obsolete.
Debuggins macros is also very tedious, inlining of functions on the other hand can be disabled.
Use macros only if it not possible to do with a function.

You have to be careful with macros, both when using them and also when defining them!
Because: macros and their parameters can have side effects!
You should write macros so that they follow the principle of least surprise.
For this reason we have a naming convention (all-caps) for macros that reveals them as such.

Multiple assessment of arguments: If foo() is a macro
then you should never pass arguments that have side effects, e.g.

foo( i++ )

is strictly forbidden!

If the macro gets expanded to:

if ( arg < Max )
x = arg;

?!

Even worse things can happen in such a case if the argument is a function:

foo( bar(x) )

How often is bar(x) called?!
What if the macro foo does also appear in the recursive function
bar() itself?!

And to add insult to injury: the program gets horribly slooooowww even if no bug occurs
because bar() gets called way too often --- and you can't even detect that any more!!

Variables in macros must definitely be chosen so that they can never
have the same name as actual variables. Such a bug can also not be found any more!
(I.a. the compiler will not even issue a warning!)
Therefore you should always use upper-case for macro-variables;
It's best if you use doubled upper-case letters or something similar.

When defining macros you have to take all possible cases and contexts
of how the macro can be used into account.
Two typical errors are:

Not terminated ifs; e.g.:

#define Bla( X )
if ( X < 0 )
X = 0;

Another bug that the user isn't even responsible for is created
if this macro gets used in another if-else:

if ( ... )
Bla( x )
else
...

Problem: the compiler apply the else to the inner if ( x < 0 )!
Remedy: put the entire if-clause in the macro in {} brackets.

Blocks of code have to be bracketed!
If the following macro

#define blub( X ) \
z = .... ; \
y = .... ;

does not get bracketed (with {}), then, when using it in the following statement, you get a bug

if ( ... )
blub( X );

that is very hard to find!

If a macro is longer then 7 lines (= instructions) then you should make a function out of it anyway
-- the compiler can inline such "short" functions.

Not bracketed expressions; e.g.:

#define Bla( X, Y ) X-Y

results in a bug that's hard to find if the macro is used in another expression, e.g.

z = Bla(a,b) * c;

The result is a - b*c, which was most likely not the programmers intention!
Remedy: #define Bla( X, Y ) (X - Y).

Another example why bracketing is necessary:

#define vmmPrintVec( V ) printf( "%f %f %f", V[0], V[1], V[2] )

results in complete nonsense (up to core-dump!) if you use it like this:

vmmPrintVec( *v )

(Priority of operands * and []!)
So in this example you have to write the macro like this:

#define vmmPrintVec( V ) printf( "%f %f %f", (V)[0], (V)[1], (V)[2] )

You should just as well try to define macros in a way that arguments are used
just once (which obviously not always works).
E.g. instead of this

Custom Functions.
If you use your own functions there will be lots of cases where certain
parameter-combinations could happen according to the code but which you know
never to happen because the function is only called with specific parameters.

But trust an experienced (and sorely afflicted) programmer:
it will happen!
(Assuming your code exceeds a certain "threshold" of about 5.000 lines.)

Therefore: everyswitch and most if's need
a default: for the "can't happen"-case!
This must at least ensure that the program provides a noticeable error message
and continues without a core dump.

System calls.
Even system calls (i.e. malloc() or open or
fork/sproc) can go wrong! Even when it can't happen.
(E.g. it can always happen that the memory or the i-node table is full.)

Never use the same file names multiple times in a software-system!
Neither for header-files nor for C-files.

The assert-macro (see man assert)
can help to increase the maintainability and also helps to find bugs faster
(even if you weren't looking for one at that position).
In addition the assert-macro explicitly highlights conditions in the code,
e.g. loop-invariants or pre- and postconditions.
Warning:
Warning: make sure that this macro is not enabled in the product version! (-DNDEBUG)

Do not use paths when including (e.g. #include<../mydefs.h>)!
Use the -I-option of the compiler instead
(then you can re-organise the libraries later on much easier without having to change all source files).
Use #include <...> for standard-header-files
(usually in /usr/include) and #include "..."
for all the others (small speed up when compiling).

The header-file should always be included in the C-file,
in which the corresponding functions or variables are actually defined.
Then, the compiler can check that the declaration still matches the definition.

Use isascii you use one of the other ctype.h-macros. E.g.

if ( isascii(*c) && isdigit(*c) )

scanf can stop before it has scanned all parameters. Check the return-value!

This forces one to actually give some thought to the case that there is no free space available.

If you use the fall-through feature of a case-statement
then you have to comment on that!
The default-statement of a case must always be present.
Avoid embedded statements. ++ and -- also count.
Although it can can make the code more readable sometimes, i.e.

Every beginner makes the following bugs --- so don't worry
if they happen to you too :) (they happened to me too):

Comparison to String-equality with

if ( strcmp(s,t) )

scanf with called-by-value parameters (results i.a. in a core-dump
at this point).
printf with a wrong format-string usually results in random output or a core-dump.
Modern compilers with the proper warnings enabled issue at least a warning meessage.

The function (or macro) abs results in garbage if you apply it to
floats or doubles -- you have to use
fabs or fabsf for that!

Generally speaking, first optimize the algorithm and not
the implementation with a few "tricks"! The compiler knows the CPU way better than you do.

Before you "tune" (optimize) the implementation you should ask yourself if the implementation is already sophisticated enough that this makes sense!9)

9)
"Premature Optimization is the Root of All Evil" -- Donald E. Knuth.

If you want to optimize, then only after a profiling! You'll be amazed where time gets lost.

First, let the compiler optimize. This is done with the following compile-/link-options:

cc -n32 -O ...

For C++-code Inlining can get you a bit of speed,
if you have lots of small get- and set-functions. You do not
have to write source in the header-file! This is done with the right compiler options:

cc -n32 O -INLINE:=ON

turns on inlining for individual files, i.e. functions are inlined within this file.

For C-code this only works, if you know that you have small(!) functions that are called a few 1000 times.

Inlining across multiple files is done like this

cc -O -IPA:inline=ON

-IPA must be specified on the compile-line and on the link-line.

If you want to know what's actually going on you do

cc -O -INLINE:=ON:list=ON

Then you get output on stderr what is being inlined.

In general, my experience is: the compiler knows very well when it's worth it!
If you still want to make sure that a particular function is inlined you do

cc -O -INLINE:=ON:must=foo,bar

(For C++ you have to specify the "mangled names" of course.)

For inlining from libraries you can use -IPA if it is a .a-Lib
(not .so) and if this library was also generated using -IPA).
Otherwise you have to use -INLINE:library=. One should also set -IPA:plimit=192,
otherwise the code gets too large (claimed someone in the newsgroup).

Who wants to know more about inlining and other compiler options for optimization does man 5 ipa
or looks it up in the insight-book "MIPSpro Compiling and Performance Tuning Guide".

Examples of pseudo-optimization

while ( *i++ = *j++ ) ;

is not faster (even more slowly) then

while ( *j )
*i = *j , i ++ , j ++;

(Even better in this case is strcpy or memcpy:))
Because:
if you use side effects (*i++) you take away ways to optimize from the compiler!
(E.g. by swapping assembler-lines.) Also strcpy() is coded very carefully in assembler.

With register short i; instead of int i; you just force the compiler to ignore
its optimized register-allocation in order to follow your register command! (If it doesn't ignore it at all.)

Inlining a function only yields benefits if they consist of 1-2 lines!
(In all other cases only the code size explodes.)

It is analogous with the factorization of functions: he who puts everything
in a single function or converts every function into a macro10) should quickly look into
CPU benchmarks!
(You can look up how expensive a function call really is in there.)

10)
OK, I admit that we did that in the Y too ---
to our apology I have to say that the compilers couldn't optimise as well (no inlining)
back then (1994) and that we simply didn't know how fast a function call really is!

The second version is faster by a factor of 10
(Because the compiler has more freedom to optimize)!

It can be extremely embarrassing if a computer scientist does not know the sixth-form mathematics.
It has happend that peaople have calculated the expression
1 + q + q2 + ... + qn in a loop!
(Geometric series)

Clumsy Coding

Avoid FPEs (floating-point exceptions). While they are usually ignored
they still cost time because the exception is still being generated and handled.
FPEs can occur among other things by calculating with uninitialized variables or NaNs.

Clums coding can ruin even the most effective algorithm!
An example:
An algorithm processes a String of length N and has a complexity of O(N*log(N)).
One intermidiate step is the concatination of k substrings of a total length of N.
Neat implementation:

If this code is run often then the performance is down the drain!
Except from that it is just very ugly to compute the square
of a number with pow instead of x*x.
This also shows that the programmer does not understand the system
that his code should become a part of --- for every graphical system
provides quite a lot of features for any possible vector-matrix arithmetic.

Use alloca(), if you need temporary memory that
isn't needed any more after the end of the function.
This is faster, the risk of memory leaks is smaller and it avoids memory clutter.
Do not use alloca if you might need lots of memory
because Unix will kill the program if there isn't enough memory left on the stack.

Nobody still programs a String-Copy, Quicksort, Hashtable,
Lists, dynamic Array, etc.!
There are good, efficient, established standard-libraries for that!
(see RTFM)
--- implementing it yourself takes too much time and is never faster
then the standard functions because those are well written in Assembler
and are tuned for speed.

Some basic rules of object-oriented (oo) design (OOD) are described
in this chapter. Most of them are language independent
(you can even implement an OOD in Assembler).

Real Optimizations

Align arrays, whose size is in the same order of a cache-line, on the same memory-boundaries.
(E.g.: one cache-line is 64 bytes long (Pentium 4), so you should align arrays of roughly that size also on 64-byte-boundaries.)

Use pre-increment instead of post-increment.
Reason: the compiler has to make copy of the object first (Copy-Ctor!),
then call the method of the object and then throw that copy away.
It is much harder for the compiler to detect that the first Copy-Ctor can be eliminated.
This is much easier with pre-increment.

Simplicity.
Both the interface and the implementation have to be simple.
The simplicity of the interface has priority over the simplicity of the implementation --
nevertheless a simple implementation is still important, especially for the maintainability.

Correctness.

Consistency.
This criteria might be the one that is the worst to measured objectively.
Correctness is still just as important as simplicity.
It might be necessary to sacrifice a bit of simplicity to achieve correctness --
but never the other way around!

Completeness.
The design / the library / the module has to cover all kinds of situations and then some more.
It is very hard to anticipate every one of them.
If the simplicity would have to suffer extremely it is better to do without completeness.

It is also important to find the right correlation
("is-a", "uses", "is-like") between classes.
It is wrong to think of inheritance first.

There is an interesting thought about completeness,
simplicity and consistency in "Worse is better":
sometimes it can be better to burden the caller with a bit of the consistency- or completeness-preservation.
Namely then when it is much easier to achieve for the caller then it is for the implementation in the library.
The only problem is "just" to find the right balance!

Liskov's Substitution Principle

Let B be a subclass of A; a piece of code is given that contains objects of class A.
Then the code must still behave exactly the same
if one replaces the objects of type A with objects of type B.
This must also be the case for all other subclasses B' of A.

It is the idea that a user of the subclasses of A can always expect
the same behaviour when using only features from Class A --
there should also be similar behaviour otherwise.

Open/Closed Principle

This principle demands that classes are both open and closed in the following sense:

they are open for extension
(by derivation or delegation);

they are closed to changes
(except extensions).

This principle aims for stability. A class shouldn't be changed any more
once it has been judged to be good by reviews, tests and practice.

However it should be designed in a way that it is extendible in case that additional features are needed.

Class or Algorithm?

Some people go too far with objectification. They make everything an object.
Maybe they think that they are especially "object-oriented" (and therefore "in").

But just like Alexandr Stepanov (the mastermind behind the STL) said:
"It is nonsense to make everything an object (a class) --
a sorting algorithm is not an object."

It is sometimes better to lay out the design so that it laid out in global algorithms
which are implemented as templates and get an additional abstraction via iterators.
That is the exact approach that the STL is using.

Graceful Degradation: The program has to continue to run as good as possible,
even under "harsh" conditions. E.g. if a constructor or a malloc() did not work
because there was not enough memory, or if a file is not there which should be there,
or if the program does not get something that it needs --
it has to continue without a core-dump!

Robustness of the source-code against application-bugs:
if someone uses your functions but didn't read the documentation very well
(there is one, isn't it?!) then the functions may not crash or output total nonsense.

Murphy's law is
Basically Murphy's law applies: if something can go wrong, it will go wrong,
and only after it delivered to the customer!

By the way: robustness is closely connected with
stability (see. bugtracking)
and continuous checking of the plausibility of the input values.

It is clear that everyone has their own style and methods of working,
like everyone has their own style of programming. However, it is imperative
that you accustom yourself to a meticulous style of working.

Meticulous programming takes (apparently) more time, but it is more effective in the end.

Every bug will get you sooner or later. (There are even bugs that emerge only after 1 year!)
This happens most of the time if you have absolutely no time to repair it. (Because of a demo, a deliver, etc.)

Even worse are bugs and unrobust software that frustrate the customer!
1 frustrated customer = 10 lost new customers.

"It doesn't do exactly what I want": but it does often enough doalmost
the same, and it would have been easy to write a few small wrappers.

"It costs too much CPU-time to call a library function":
You only hear that from people who never profiled their program.

"I didn't know that the function / library / code exists":
Competent programmers know what's in their toolboxes, their Unix
and browse the PD-repositories every now and then.

"I would have done it different": is the triumph of personal taste over professional programming.

The "Not invented here" syndrome,
the "Not good enough" syndrome, and the
"Not understood here" syndrome.

Conclusion: you need really good reasons if you want to reinvent the wheel.
It is almost always faster, more robust and more seminal to use or improve an existing wheel.

How to find the code to your problem?
First you look into the man-pages via man -kkeyword
("apropos" button in xman). Then you search in the online books
(insight and infosearch). After that you ask your colleagues.
You can often find useful code after a short internet search or an inquiry
in the appropriate newsgroup e.g. comp.*.{source,software}.* (Read the FAQ first!).

What kinds of code-theft (this is called code re-use in software engineering) are there?

Pipes: on of the revolutionary concepts of Unix.
If you write a "tool" that is mostly used as a filter then it should definitely be written
in a way that it can read/write stdin/stdout; you can use it in a pipeline in that case.

Modification of the Source.
Advantage: maximum flexibility; you can dispose of code that is not needed.
Disadvantage: Maintainability is hard. You always have to maintain both versions
of the source, bug-fixes in on version must usually be ported "by hand" to the other one.
This is often not done because "there is no time".
Consequence: the gap between the two gets wider and wider until it is impossible
to integrate changes from one version to the other.

Libraries:
Are in many ways the best way to write reusable code.
Although you have to say that it is hard to design a clean interface
and that it can be very hard to impossible to improve a bad interface later on
once the library has a certain distribution.

Templates:
This does not mean the C++ templates, but "code-skeletons".
E.g. is the parsing of command-line-arguments a frequent candidate for this kind of code re-use
(see ~zach/KnowHow/c), but also man-pages or "large" makefiles.

include: Code re-use via #include is prohibited!

Call:
Sometimes you can make your life easy if you just call an existing program
via system() or popen().
On the downside of that is that the data exchange is often a bit clumsy
and the call takes considerably longer then a library call,
It is a common beginner's mistake to use system() or
popen() for odds and ends, e.g. for a simple "ls" or "rm".

How to hunt bugs?

Unfortunately there is no strategy that always works and gets you there in the fastest way possible.
Here are a few rules of the thumb:

It is best not to make any.
A good resource (which has already saved me several hours of bug-hunting)
is the compiler option -Wall (using gcc/g++). This yields a whole lot
of warnings that indicate potential bugs or non-portable code.
(Of course, you have to turn off some unnecessary warnings with -woff.)
The new compiler even noticed the bug that the printf-format-string
does not match the arguments!

If it is a "sporadic" bug, try to find a situation (a "problem instance")
in which it always occurs (or as often as possible). If that does not work only brooding helps!

In that case, try to find a "minimal" problem instance or input,
so that the bug just yet but still reproducibly occurs. In the case of computer graphics
"minimal problem instance" usually means: a small scene, a few points, small objects,
a few objects, minimal configuration of the program, etc.

Try to determine the symptoms accurately; or exactly the situation
or the sequence of events, in which the bug occurs.
Is each of the events necessary to cause the bug?

Then try to zero in on the place in the sequence in which the bug occurs.
This can be a function or a section of a function (Commands stop in function and s or rather n in dbx).

an interaction bug which occurs because different parts of the program/system
are not working together properly even though each for its own is working fine.

a memory-bug which occurs because of memory-corruption
(some array is too small or maximum-bounds are not being checked
or pointers are being used which are not valid (any more))

you can see if a pointer is still valid if it points to an address
which can be divided by 4 (or even 8) (for non-chars).

incomplete distinction of cases; these bugs are very hard to find and recognize.

a graphics-bug

an assumption-bug (somewhere is an assumption about the state of some variable
or data-structure which is violated -- for whatever reason)

Tools for the bug-hunt:

The debugger is still the most important tool (not printf).
Therefore:
learn to use your debugger efficiently!
dbx is in my opinion still the tool
with which you can debug the fastest (in 99% of all cases) 12),
even though it doesn't have any fancy icons and you have to remember a few more commands.

12)
apart from the fact that it is present (in slight variations), on all Unixes

You start dbx with the dbxprogram.
The most important commands:

r options

start the program with options as parameter.
Once you specify the options you only have to type r.

t

show stack trace.

W

show location in source (if source is present).

stop in function

sets breakpoint to the start of function.

stop at [&]function

sets breakpoint before the first instruction of function.
The prologue of he function is still executed in case of stop.
This way you can securely find out what values the argument registers have.

you can get online-help with
help, help most_used, help cplusplus_names.

Code-instrumenter:
purify often helps if you suspect a memory-bug.
(Low-cost-alternative: electric fence.)

ctrace is an open-source code-instrumenter which modifies a C-file
in such a way that each line is displayed with the modified variables
while the program runs. (Does not work for C++, I think. Is there a PD-tool?)
Documentation: see man-pages.

Compiler: different compiler-options (SGI).

-trapuv
ensures that local variables are initialized with a value
which guarantees a core-dump, if these variables are used before they are set.

-TENV:large_stack
does sometimes help if the stacks gets corrupted or flows over.

-fullwarn
recognizes a lot of bad/nasty code which is okay in principle
but is usually a bug or bad programming-style (e.g. wrong type of parameter).
Some warnings are unnecessary but you can disable them globally with -woff.
If a warning does only make no sense at a few places then you shouldn't
disable them globally but instead targeted via #pragma woff.
By the way, you can avoid the warning "Parameter not used"
(or something like that) if you simply omit the name of the parameter in the prototype.

Run-time Loader (rld):
this ensures at the start of a program that all libraries are linked and references are unravelled.\
Useful debugging-flag:
setenv _RLD_ARGS "-clearstack". If your program works after this
then you're not initializing some variables!

Libraries: (so called intercept-layers).
malloc_cv is very good to find memory-corruption.
It is linked fast into the program, no instrumentation is necessary
and it is sufficiently mighty. (See man-page for more info.)

Apropos "pondering": the right mixture of intuition, combined with
a quick start of the debugger and a few targeted breakpoints
is most often the fastest way.
It takes a long time to develop this intuition but it is worth it
and constitutes a good programmer.
Although you need to have the "big picture" of the involved software for this to work.

As a programmer you have to get used to reading the documentation.
This can be man-pages, insight-books, white-papers or whatever!
You also have to get used to reading them thoroughly but still fast.

Reading of man-pages requires a bit of practice; but it's not that hard
once you get the idea and you can find what you need very fast after it.
And before you start to curse about the "damn-man-pages" ---
wait until you have to write documentation yourself!

Man-pages that you should know as a Unix-user: ls, cp, ln, tar, vi (or another editor), find, the man-page of your shell,
ed (the part about regular-expressions),
grep,

A little word about the tools you will need as a programmer in daily life.
You need to master four tools as a programmer: your editor (whichever),
the compiler, the debugger and makefiles.
(You also demand from every good craftsmen that he knows and is proficient with his tools.)

The most important tool as a programmer whatsoever is the editor.
Your editor is a tool for you that shall help you to program fast and efficient.
It should have the following features in my opinion:

It should have sufficiently mighty features:
search-and-replace of regular-expressions, over the entire text and also only over parts of it;
macros; automatic indentin and exdenting; repeating of commands and command- and search-histories;
support of tags; it should be possible to reach the declaration of an identifier with a few keystrokes
or mouse-clicks if the cursor is over that identifier (regardless whether type, variable or function);
call of macros from the editor and support of handling the error-list of the compiler;
syntax-highlighting is nice to have (not only for C); key-mapping and abbreviations;

It should be available on every platform.
(Remember that you will most likely not work on SGI for ever.)

It should also work without graphics, i.e. have a purely text-based mode, which you can control.
(Sooner or later you will be in the situation that
you sit in front of a vt100-emulator and hve to edit something remotely...)

In my opinion only vim (the upwards-compatible successor of vi)
and emacs fulfil these conditions.
Vim also has the advantage that vi is guaranteed to be present on every Unix system.
And emacs has the disadvantage that most people can't even use the pure text-mode.
14)

14)
Except these to advantages/disadvantages the choice of the "right"
editor is nothing but a choice of "character":
nedit and xemacs are good for people who want to start typing
right away and have no problem with holding down the control- and/or alt-key
in order to execute a command. Vim is good for peaople who want to type
as little as possible in order to give a command to the computer
but don't have a problem with typing "i" or "o" before they can start typing.

Another important tool is a man-page-reader.
I recommend xman or, even better, tkman.

Every now and then you should run purify over your code.
This is a tool to find memory-leaks and memory-corruption.
(Low-cost-alternative: electric fence.)