62
C/C++ Programming Rules DRAFT

C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

Embed Size (px)

Citation preview

Page 1: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

C/C++ Programming Rules

DRAFT

Page 2: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

Page 3: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFTC/C++ programming rules

Technical Reference Manual

Version: 1.0SVN Revision: 52580

June 2, 2018

Page 4: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

C/C++ programming rules, Technical Reference Manual

Published and printed by:DeltaresBoussinesqweg 12629 HV DelftP.O. 1772600 MH DelftThe Netherlands

telephone: +31 88 335 82 73fax: +31 88 335 85 82e-mail: [email protected]: https://www.deltares.nl

For sales contact:telephone: +31 88 335 81 88fax: +31 88 335 81 11e-mail: [email protected]: https://www.deltares.nl/software

For support contact:telephone: +31 88 335 81 00fax: +31 88 335 81 11e-mail: [email protected]: https://www.deltares.nl/software

Copyright © 2018 DeltaresAll rights reserved. No part of this document may be reproduced in any form by print, photoprint, photo copy, microfilm or any other means, without written permission from the publisher:Deltares.

Page 5: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

TitleC/C++ programming rules

Client Project Reference PagesDeltares 11200568 - 54

Classificationpublic

KeywordsC/C++

SummaryC/C++ programming rules are defined to guarantee the reliability and stability of a modellingsuite. The aim of these C/C++ Programming rules is to meet future demands of users withrespect to functionality, flexibility, accessibility, modularity and performance.

References-

Version Date Author Initials Review Initials Approval Initials0.01 2005 Arjen Markus Jan Mooiman Arthur Baart1.00 28 Sep 2017 Arjen Markus Jan Mooiman Joost Icke

Statusfinal

Deltares iii

Page 6: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

C/C++ programming rules, Technical Reference Manual

iv Deltares

Page 7: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

Contents

Contents

1 Declarations 11.1 Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.2 Global (external) variables . . . . . . . . . . . . . . . . . . . . . . . . . . 11.3 Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21.4 Type variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31.5 Macros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31.6 Prototypes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41.7 Pointer prefix . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4

2 Control statements 52.1 General . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52.2 Loop constructs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52.3 Selections via switch/case . . . . . . . . . . . . . . . . . . . . . . . . . . 82.4 Conditional statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92.5 Subroutines and functions . . . . . . . . . . . . . . . . . . . . . . . . . . 102.6 Error handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112.7 Using the C preprocessor . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

3 Using I/O 153.1 Opening and closing files . . . . . . . . . . . . . . . . . . . . . . . . . . . 153.2 Standard input and output . . . . . . . . . . . . . . . . . . . . . . . . . . . 153.3 Reading and writing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15

4 Expressions and assignments 194.1 Varargs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194.2 True and false . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194.3 Parentheses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194.4 Implicit assignments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204.5 Conditional expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204.6 Loop conditions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214.7 Token pasting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214.8 Debug statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214.9 General . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214.10 Errors and functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224.11 Pointers and functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224.12 Type casting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224.13 NULL pointers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23

5 File organisation 255.1 Source files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 255.2 Include files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26

6 Layout, internal documentation 296.1 Naming conventions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 296.2 Language . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 296.3 Order of program text parts . . . . . . . . . . . . . . . . . . . . . . . . . . 296.4 Comment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 306.5 Alignment of declarations . . . . . . . . . . . . . . . . . . . . . . . . . . . 316.6 Statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 316.7 Assignments and expressions . . . . . . . . . . . . . . . . . . . . . . . . . 316.8 Letters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 316.9 Line length . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 316.10 File length . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32

Deltares v

Page 8: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

C/C++ programming rules, Technical Reference Manual

6.11 Function length . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 326.12 Spaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 326.13 Braces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 326.14 Indentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336.15 Empty lines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336.16 Fileheader . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336.17 Function header . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336.18 Functions and parameters . . . . . . . . . . . . . . . . . . . . . . . . . . 346.19 Variable/constant . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 346.20 Version information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35

7 Recommendations 377.1 Source and include files . . . . . . . . . . . . . . . . . . . . . . . . . . . . 377.2 Names of routines and functions . . . . . . . . . . . . . . . . . . . . . . . 38

8 Prohibited statements and constructions 418.1 Forbidden data types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 418.2 Null statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 418.3 Forbidden standard functions . . . . . . . . . . . . . . . . . . . . . . . . . 418.4 Illegal use of pre-processor constructs . . . . . . . . . . . . . . . . . . . . 418.5 Illegal use of functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43

References 45

A Set/get functions 47

B Examples 49B.1 Example C module (.c) . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49B.2 Example C header file (.h) . . . . . . . . . . . . . . . . . . . . . . . . . . 51

vi Deltares

Page 9: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

1 Declarations

1.1 Variables

Each variable must be declared on a separate line.

Each variable must be explained by means of a comment string. This comment string will beplaced directly after the declaration or definition and may be continued on one new line at themost.

Local variables must be declared at the beginning of a function and also at the beginning of ablock. All basic variables (int, float, char, long, short and double) are initialised at declaration.Don’t assume the compiler will initialise variables at zero or blanks for you. Exceptions to thisrule are static and external variables, according to ANSI C they will always be initialised atzero. Mind the usage of already defined functions.

Examples:

Compliant Not compliant

long lower = 0; /* Lower bound */ int lower, upper, step;long upper = 300; /* Upper bound */ float eps;long step = 20; /* Step size */ char c;float eps = 1.0e-5; /* Smallest difference */

char c = ’\\’; /* Escape char */

1.2 Global (external) variables

Global variables are inevitable from time to time:

� It may be necessary to keep the state of the program in a globally available structure,because in most user-interfaces the callback functions that are typically used to handlewindow events do not allow an arbitrary argument list.

� It may be necessary to pass information on to higher-level routines, for instance errorconditions and there is no way (because of third-party libraries) to handle this informationflow via an argument that is passed by reference.

� When using such tools as Yacc and Lex, information is mainly transferred via global vari-ables, as there is no other way.

Therefore we need an etiquette for the use of global variables. This etiquette is given below:

The use of global variables is forbidden (with or without the static attribute), unless they arecontained in a structure. The definition of this structure is contained in an include file as aseparate user-defined type (typedef).

Any routine seeking to use this globally available structure, should obtain a pointer to thisstructure either via its argument list or via a function call:

In the include file:

/* Definition of the program state */typedef struct _ProgramState {

...

Deltares 1 of 54

Page 10: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

C/C++ programming rules, Technical Reference Manual

} ProgramState, *ProgramStatePtr;/* Auxiliary function - obtain the program state */ProgramStatePtr *GetProgramState(void);

In some routine:

long routine( ..., ProgramStatePtr statep, ...)

{.../* Update the program state */...

}

Or alternatively:

long routine( ...)

{ProgramStatePtr statep;statep = GetProgramState();/* Update the program state */...

}

The global variables within this structure can best be updated via get/set routines, rather thandirect assignments to the individual fields, as this makes the application less susceptible tochanges in the structure.

One advantage of using structures and pointers to these structures is that, should it becomenecessary to distinguish several such items, one can simply allocate a new structure of thistype and fill it.

1.3 Constants

The best way to define constants is to declare them with the const qualifier. This way youspecify that its value will not be changed. Using the const qualifier for an array it says thatthe elements will not be altered of when used for array arguments it indicates that the functiondoes not change that array. An advantage is the compiler checking of the variables that havebeen declared with the const qualifier.

Examples:

const long number = 42; /* Crucial number */const double e = 2.71828182845905; /* Math’s exp(1) */

const char msg [ ] = "warning~: "; /* Prefix for messages */

long KeyValue( const char [ ] );

2 of 54 Deltares

Page 11: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

Declarations

1.4 Type variables

Types play an important role in C programming. C provides a facility called typedef for creatingnew data type names, to be used as more explanatory synonyms. Especially use typedef formulti-dimensional arrays, pointers to functions or pointers to user-defined structures.

Caution

The scope of some basic C-types is platform dependent or even compiler dependent. For thatreason porting an information system from one platform to another may cause adjustmentsto that information system. This is hardly avoidable in those cases where software layers arevery close to the ANSI library. Therefore the usage of typedef’s is depreciated for the ’lower’software layers.

Some examples of type definitions:

typedef int Length; /* type declaration */Length len; /* length of a word */Length maxlen; /* maximum length */

typedef char * pString; /* type declaration */pString p; /* local string */pString lineptr[MAXLINES] /* string pointer array */

1.5 Macros

Use macros (#define) to define constants and only leave trivial constants (such as 0 and 1)unchanged in the code. Preferably use a module prefix for a macro from a dedicated module.

Always use capitals when naming the macro and take care not to redefine a predefined macrolike BUFSIZ (defined in stdio.h) or M_PI (often defined in math.h)

Always use brackets in expressions in a macro. This will avoid an incorrect evaluation of theexpression.

Using a set of macro definitions where an itemized type definition can be used is not allowed:

Compliant Not compliant

enum months {

JAN = 1, #define JAN 1

FEB, #define FEB 2

... ...

DEC }; #define DEC 12

Note: Beware of side effects when using a macro, for instance when increments might beused in the parameters to the macro.

The description of a #define constant or macro has to placed before the definition, forexample (otherwise the comment might become part of the macro’s value):

Examples:

/* Code for closing an experiment-object */#define CLS_EXP_OBJ 100

Deltares 3 of 54

Page 12: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

C/C++ programming rules, Technical Reference Manual

1.6 Prototypes

When using an (external) function the existence of a declaration of the so-called function-prototype is required. It is an error if the definition of a function or any uses of it do not agreewith its prototype. An important reason for function prototyping is the improving softwaremaintenance and type checking by a standard-compliant compiler.

Function prototypes have to be declared in a header (*.h) file. The usage of header fileswith function prototypes needed may only be achieved with an #include statement. To besure the function prototypes and function definitions are the same the header file with functionprototypes must also be included in the .c file with the function definitions.

Use the const keyword for function parameters that will not change and the keyword void fora function that returns no value. This will explain something about the parameter as wellas the function and, moreover, the compiler can check for certain errors that violate theseconstraints.

If a function has no parameters, the keyword void (instead of empty parentheses) has tobe used. Leaving out void means the list of parameters can be anything – checking by thecompiler is then impossible.

Note: The rules mentioned above concern all functions.

Examples:

void GiveMessage (long state,long message_type,char * text );

1.7 Pointer prefix

For naming of variables which will be used as pointers a type prefix ’p’ is required. The prefixis the first character must be placed before the variable name.

Examples:

double * pWlevel; /* water level */long * pMmax; /* size M-direction */char ** pstrings; /* Array of strings */

4 of 54 Deltares

Page 13: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

2 Control statements

2.1 General

Each language has its so-called idiom (Kernighan and M., 1988; Hatton, 1995; Kernighan andPike, 1999). For C (and C-like languages, such as C++ and Java) this includes:

� The way for-loops are normally set up� The use of certain functions, especially the functions from the standard library� The use of return values, such as 0 and 1

Knowing the idiom and using it is crucial: if you do not follow that style of programming, thereaders of your programs can very easily get confused and make mistakes that could havebeen avoided.

For instance, a function that is able to do its job will normally return zero to indicate this.So, using a function that returns 1 instead to indicate everything was fine, goes against thegrain. Similarly, it is customary in C to use counters and indices that start at zero, rather thanat 1. Use this and similar conventions at all times. This chapter helps identifying the mostcommon idiom and specifies several additional constructions and keywords. All are meant tohelp creating robust and maintainable programs.

A corollary to the above statements is: Use the standard functions whenever possible. Thisapplies in particular to string manipulation functions (such as strcmp()) and character typefunctions (such as isalpha()). Besides the ones defined in the ISO C standard, we also definethe following as part of the OMS portability library:

� mkfilename() to construct the full path (directory and name) for a file from its parts� strdup() to duplicate a string

Several general restrictions apply:

� Logical expressions must be kept simpleIf the expression requires the evaluation of more than two sub-expressions (so at leasttwo logical operators), it must be split into parts (for instance, by assigning partial resultsto variables with a meaningful name).

� None of the expressions may have side effectsThe use of side effects, especially in compound logical expressions, can lead to difficultsubtleties, because C programs will evaluate such expressions in a lazy manner. Putsimply: never use side effects (increment operator etc.), unless explicitly allowed in specialconstructs by this standard.

� Keep the nesting depth within boundsIf you find that you need more than, say, four levels of nesting, you are probably better offputting the inner constructions in a separate function or subroutine.

2.2 Loop constructs

C has three different loop constructs:

� for-loops to loop over a predefined set of values or items� while-loops to loop until a certain condition is no longer valid� do-while loops to loop at least once

Deltares 5 of 54

Page 14: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

C/C++ programming rules, Technical Reference Manual

For-loops

The for-loops have two common forms:

� Looping over a set of integers:

for ( i = 0; i < n; i++ ){

...}

Crucial aspects are:

� The index starts at zero� The index is incremented by 1 in the third part of the for-statement, using an increment

operator� The condition is that the index must be lower than a constant value� Neither the index nor the upper bound are changed within the body of the loop� You may get a variation to this type of loop by iterating backwards:

for ( i = n-1; i >= 0; i-- ){

...}

In all cases: observe the standard expressions

� Looping over a set of items (a linked list for instance):

for ( elem = get_first( list );elem != NULL;elem = get_next( list, elem ) )

{...

}

Crucial aspects are:

� The initialisation part picks up the first element and the iteration part picks up the nextone.

� The loop is continued as long as there are elements in the set that have not been visitedyet.

� The set is not changed during the iteration, because this could lead to very awkwardbehaviour (e.g. if you append a copy of the current element, the iteration would neverend!)

While-loops

The while-loop has three acceptable forms, whereas the do-while loop has only one:

while ( some_condition ){

...}

6 of 54 Deltares

Page 15: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

Control statements

with two special cases:

� Reading a file and the equivalent to the infinite for-loop):

while ( fgets( string, sizeof(string), infile ) != NULL ){

...}

The reason to allow this construction is that it is accepted idiom (cf. Kernighan and Pike) andthat alternatives would require more logic or a slightly awkward sequencing (reading the lineat the end of the loop for instance).

� The equivalent to the infinite for-loop:

while ( a < b ){

...}

Do-while loops

Do-while loops are not allowed. Their effect can be achieved with ordinary while loops.

Notes on the above� The condition should be used to terminate the loop whenever possible, instead of a break

statement.� The choice for an infinite for-loop or an infinite while-loop is not a matter of taste within

OMS. Within OMS we have chosen for the infinite while-loop, as this is syntactically theclearest one.

� The idiom of the for-loop excludes the use of multiple assignments in the initialisation anditeration.

� The index variable must be an integer. Reals, characters or pointers to characters are notallowed. Otherwise, the iteration is not well defined.

Examples

Here are some examples of loops that are not allowed and their corrected alternatives:

� Multiple assignments in the various parts of the controlling part of the for-loop

Deltares 7 of 54

Page 16: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

C/C++ programming rules, Technical Reference Manual

Compliant Not compliant

j = 0;for ( i = 0; i < n; i++ ){

...j ++;

}

for ( i = 0, j = 0; i < n; i++, j++ ){

...}

(Easy mistake, edited version of the above)

for ( i = 0, j = 0; i < n; j++ ){

...}

The reason for this is that is very easy to make mistakes that are hard to spot (see the secondexample above).

� Side effects are used to eliminate the while-loop’s body:

Compliant Not compliant

pstr = string;while ( *pstr != ’\0’ ){

*pstr = toupper( *pstr );pstr++;

}

pstr = string;while( (*pstr++ = toupper(*pstr)) != ’\0’);

2.3 Selections via switch/case

Switch statements should be used instead of if-else-if constructions if the condition involvesthe values of a single integer or character. They are more efficient and, above all, much morereadable than long if-blocks.

We make the following notes:

� Each case must be terminated by a break statement or by a comment that a "fall-through"is required, so that the lack of the break statement is clear.

� Do not try to be clever, a fall-through works best if the first case has only a few statementsor, preferably, none at all that are specific to the first case. The second case should haveno code that is exclusive for that case.

� All switch statements must have a default case. If this is not supposed to appear inpractice, it must contain a body with proper error handling to indicate that fact.

� Note the indentation: the switch, case, and default keywords should be vertically aligned.� Use symbolic names as provided by the enum construct, rather than hardwired numbers.

8 of 54 Deltares

Page 17: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

Control statements

Examples:

Compliant Not compliant

enum {CASE0,CASE1,CASE2,CASE3

};

switch ( var ){case CASE0: /* Fall through */case CASE1:

printf( "Typical cases\n" );break;

case CASE2:pstr = "Case 2";printf( "%s\n", pstr );break;

case CASE3:pstr = "Case 3";printf( "%sn", pstr );break;

default:fprintf( stderr, "Impossible case!" );break;

}

switch ( var ){case 0:case 1:

printf( "Typical cases\n" );break;

case 2:pstr = "Case 2";

case 3:if ( var == 3 ) pstr = "Case 3";printf( "%s\n", pstr );break;

}

2.4 Conditional statements

General conditions can be applied in if-statements. There are a small number of restrictions,though:

� Do not make the if-blocks too longif-blocks with several else-if statements will quickly become unmanageable. Limit them toat most 30 lines (so half a page on paper).

� If-blocks with at least one else-if should always have an explicit else branchBecause the if-block is compound, one must catch the possibility that none of the condi-tions holds. If there is no reason to assume this ever to be the case, then treat it just asthe impossible default case in a switch-statement.

Example:

if ( strcmp( string1, string2 ) == 0 ) {...

/* First case */} else if ( strcmp( string1, string3 ) >= 0 ){

.../* Second case */} else {

.../* Default processing required! */}

Deltares 9 of 54

Page 18: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

C/C++ programming rules, Technical Reference Manual

2.5 Subroutines and functions

All rules concerning the use of subroutines and functions could be summarised as:

Be as explicit as possible in defining the interface

More specifically:

� Use the keyword "const" to indicate that arguments will not change. This enables thecompiler to check illegal or unexpected changes.

� Do not locally change arguments that have been passed by value, even though thechanges will have no effect in the calling routine. It is bad programming.

� Consider the difference between *arg and arg[]. The first can be used as a synonym forpassing by reference or for passing an array. The second explicitly states that an array isexpected.

� All subroutines and functions must have a proper prototype.� Use the ISO style for defining the arguments, not the older K&R style:

Compliant Not compliant

long sample(long * a, /* Parameter a */long b, /* Parameter b */long c ) /* Parameter c */

{...

}

int sample( a, b, c )int *a;int b, c;{

...}

� Use an explicit return statement if the function is supposed to return a value. Do not usean explicit return if it does not:

Compliant Not compliant

long sample(long a[], /* Array a */const long b, /* Param. B */const long c ) /* Param. C */

{long retval = 0; /* Return value:

0: OK;< 0: error */

long b2;b2 = 2*b;...a[0] = b2 ;a[1] = c ;a[2] = 0 ;return retval;

}

int sample(int *a,int b,int c )

{b = 2*b; /* b changed! */a[0] = b; /* a is array */a[1] = c;a[2] = 0;

}/* returns no value! */

10 of 54 Deltares

Page 19: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

Control statements

2.6 Error handling

The following rules apply:

� Check preconditionsUse the standard macro assert() to indicate crucial preconditions, both as a means of doc-umentation and to terminate the program, should there be no other solution (this requiresthe use of the standard pre-processor macro NDEBUG).

� Use return codes and error parameters consistentlyThe protocol for the use of return codes and error parameters is summarised in the tablebelow.

Type of returnvalue

Value in case of er-ror

Remarks

Integer (status) -1 The standard library uses the value zero toindicate everything was okay and values un-equal to zero to indicate an error.

Pointer NULL Routines that return a pointer to memorycan only return a NULL to indicate some-thing was wrong.

Other (also integersthat are not a status)

- Always use an explicit error parameter tocommunicate an error condition. If you havea choice, choose a negative integer value toindicate something went wrong.

� Do not use the external variable errnoThe protocol concerning the variable errno is rather complicated. Proper use of this proto-col would assume that any function uses this protocol correctly and that all programmersunderstand it. This is an illusion. Therefore use the protocol outlined above.

� Document what happens in case of an errorIt is important to document what happens to the output arguments (if any) in case of anerror. If a programmer expects values to be set to a reasonable value and the argumentsare simply not touched, then problems will occur. Therefore the error handling must bemade explicit.

� Use the special macros __FILE__ and __LINE__ to communicate where "impossible"conditions occurredVia the referred macros it is possible to automatically include the position in the sourcecode where an impossible condition occurred. This does not carry the same informationas a full stack trace, but it saves searching for the right place:

default : /* Should never occur */fprintf( stderr, "Line %s in %s: Impossible case!", __LINE__, __FILE__ );

Even better (the special macros are caught in a standard macro):

#define INVALID_STATE \fprintf( stderr, "Line %s in %s: Impossible case!", __LINE__, __FILE__ );

default : /* Should never occur */INVALID\_STATE;break;

Deltares 11 of 54

Page 20: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

C/C++ programming rules, Technical Reference Manual

2.7 Using the C preprocessor

The C preprocessor allows, in principle, many constructs that add power to the C program-ming language. However, caution is required, as the conditional statements #if, #ifdef etc.essentially create multiple versions of the source code in one single file. This means that theuse of pre-processor constructs should be restricted:

� Macros to define constant values are allowedStatements like:

#define BUFFER_LENGTH 255

are allowed, but consider the following alternatives:

� Using the enum construction to define numerical constants by name (strictly speaking:itemized values are not integers)

� Using const variables

The advantage of these alternatives is that the compiler can produce better diagnostics if theyare used wrongly.

� Macros to define functions are not allowedMacro functions like:

#define veclength(a,b) sqrt((a)*(a)+(b)*(b))

are not allowed, because there is virtually no advantage for these functions to ordinaryfunctions, and the compiler can not always check that the construction is correct. Debug-ging them is also much more difficult.

� Creative use of the preprocessor, for example to avoid repetitive code, is allowed, providedthis type of use is well documented.Practical examples of such use are:

� Interface definitions that have to take of platform-dependencies (the interfacing betweenFortran and C for instance)

� Set and get functions for the individual fields of large structures (see Appendix A):#define set( "name", value) ...

rather than a large number of functions like:1

void name_set( value ) { ... }

� Conditional preprocessor statements should not be used, unless to capture platform de-pendenciesSuch statements may certainly not be used to:

� Hide currently unused (old?) code fragments/* Old code - should be removed one of these days */#if 0x = y*y;#endif

� Select or deselect debugging statements/* Debugging code - needs some reworking though */#if DEBUGONfprintf( stderr, "x = %f\n", x );#endif

The reason is that such code would not get compiled and would not evolve with the rest.Hence after a cycle or two of maintenance the code is outdated and it probably will notcompile correctly. A better solution is to use an if-statement with a more or less trivialcondition:2

1 This is to some extent a matter of taste. In OO environments the emphasis is very much on such smallindividual set/get routines, rather than a single pair that selects a field.

2An alternative that does use a macro, is presented in chapter 7.

12 of 54 Deltares

Page 21: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

Control statements

if ( debug_on ){... /* Debugging */}

Deltares 13 of 54

Page 22: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

C/C++ programming rules, Technical Reference Manual

14 of 54 Deltares

Page 23: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

3 Using I/O

The use of external files in C has very similar problems as in Fortran or Java: the files mayor may not exist, reading may or may not cause run-time errors and so on. Yet the details ofthese problems differs from the other programming languages and this chapter means to helpavoid them by imposing a number of rules.

3.1 Opening and closing files

The following rules apply:

� Check that fopen() does not return NULLIf it does, the file could not be opened. Take proper action.

� Close the file in the same routineFiles opened in one routine should also be closed in that routine. If not, the file pointermust be handed to the calling routine. Otherwise the file pointer will be lost and the filecan never be closed properly.

� Never use fixed file namesPut the names of the files in variables (not macros). These can be changed easily as theywill be found in one standard section of the source files.

� Compose directories and file names via a special routineRely on the OMS standard routine mkfilename() to take care of the platform-dependentissues regarding the separator character and such.

� Use string variables of length PATH_MAX to store the filenamesThe macro PATH_MAX is commonly defined to the maximum allowable size of a file nameincluding the directory etc. Using this length guarantees that the name will always fit.

3.2 Standard input and output

The following rules apply:

� Reopen stdout, stderr if necessaryUnder MS Windows, graphical user-interfaces have no access to a useful console. Hence,use the freopen() function to redirect output to some file.

� Use stdin only in non-GUI programsIf you need user interaction, consider using a graphical user-interface. Never combinestdin and a graphical user-interface - this is very problematic under MS Windows.

� Use fgets() in stead of gets()If you read from stdin, always use fgets(), because with this function you have control overthe length of the string to be read.

3.3 Reading and writing

The following rules apply:

� Read a file line by line using fgets()If you use fscanf(), you face an almost insoluble problem with line ends: the file positionwill stay on the previous line (if that is long enough), without the program being able todetect this. With fgets(), you have the benefit of being able to check that the end-of-linehas been reached or not. Then use sscanf() to split it in the desired pieces.

� Check end-of-file with the feof() macroNever use the EOF return value, because that is not reliable.

� Make sure the buffers used in sprintf() are large enoughAs C does not provide any run-time checks on strings, you are yourself responsible forkeeping within the bounds of a buffer. This can be facilitated by avoiding "open-ended"

Deltares 15 of 54

Page 24: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

C/C++ programming rules, Technical Reference Manual

formats like %f and %s (see below).� Use input format like %d and %f

To give the user the freedom he or she wants, use as unspecific a format as possible. Thesscanf() routine will make sure that it gets parsed correctly.

� Never use an output format like %fInstead, %#13.6g and %#22.15g (or %12.6g, %21.15g if you do not care for exact length)are preferred for float and double reals.The problem with formats like %f is that largenumbers are written with a lot of digits (see the example). The alternative format uses thehash sign (#) to make sure that the decimal point is always present and that trailing zeroesare maintained.

� Keep formats simpleThe printf() family of routines defines a huge set of formats but not every programmer isfamiliar with the possibilities. Hence stick to the mainstream, because otherwise othersget confused (this is especially true with formats like %*s). If you need to use the moresophisticated formats, document their use via appropriate comments.

� Consider using automated tools like Yacc and Lex for reading filesTools like Yacc and Lex can produce robust reading routines. Their use is especiallyrecommended if the input consists of more than simple numbers.

The example below shows what happens if you go against some of these rules:

The input file is:

A line of text

1.0 # One real value1 # One integer value

The naïve implementation is:

#include <stdio.h>#include <stdlib.h>

int main( int argc, char * argv[] ){

FILE * infile ;long ivalue ;float rvalue ;char string[100];

infile = fopen( "example.inp", "r" );

if ( infile != NULL ){

fscanf( infile, "%s", string ); /* %s reads a single word */fscanf( infile, "%f", &rvalue ); /* %f reads the next word! */fscanf( infile, "%d", &ivalue ); /* %d reads the third word */

printf( "String: %s\n", string );printf( "Real: %f\n", rvalue );printf( "Integer: %d\n", ivalue );

rvalue = 1.0e20;printf( "Big real: %f\n", rvalue ); /* %f uses as many positions as necessary */fclose(infile);

}

16 of 54 Deltares

Page 25: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

Using I/O

return 0;}

which, results in the following output:

String : AReal : 0.000000Integer : -268440104Big real : 100000002004087734272.000000

The explanation for this is simple:

� The format "%s" reads a string until a white space character is encountered, hence only"A" is read. As the file position is not moved to the next line but left at the word "line".This is then read as a real value, which fails. The value for the integer variable may be theresult of an implicit conversion from characters to integers, as these two data types areclosely related in C (for historical reasons mostly, never use this fact implicitly!)

� The large real is written in decimal form, giving a very long string. This can not be con-trolled via %12.3f or comparable formats.

The correct implementation, with the above rules, is:

#include <stdio.h>#include <stdlib.h>

int main( int argc, char *argv[] ){

FILE * infile ;long ivalue ;float rvalue ;char buffer[100];char string[100];

infile = fopen( "example.inp", "r" );

if ( infile != NULL ){

fgets( buffer, sizeof(buffer), infile );sscanf( buffer, "%s", string );

fgets( buffer, sizeof(buffer), infile );sscanf( buffer, "%f", &rvalue );

fgets( buffer, sizeof(buffer), infile );sscanf( buffer, "%d", &ivalue );

printf( "String: %s\n", string );printf( "Real: %12.6g\n", rvalue );printf( "Integer: %d\n", ivalue );rvalue = 1.e20;printf( "Big real: %12.6g\n", rvalue );fclose(infile);

}return 0;

}

which results in the more expected output:

String : A

Deltares 17 of 54

Page 26: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

C/C++ programming rules, Technical Reference Manual

Real : 1Integer : 1Big real : 1e+20

18 of 54 Deltares

Page 27: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

4 Expressions and assignments

In this chapter some requirements concerning C programming can be found in relation toexpressions and assignments. By eliminating complex constructions and constructions whichare error prone the chances to make errors will be reduced. Also some constructions inwhich the behaviour of C programs are undefined are excluded. Uniform C code is moreunderstandable and easier to maintain. As a consequence porting the programs to otherplatforms becomes easier as well.

4.1 Varargs

Modules with a varying number of parameters must be avoided as much as possible. Only ifthere is no other solution, are they allowed and then the use of varargs is required.

4.2 True and false

Normally the macros FALSE and TRUE are defined in a some sort of standard header file. Ifthey are not yet defined in some header, file define them like this (no other similar definitionsmay be used):

#if ! defined(FALSE)#define FALSE (0)#endif#if ! defined(TRUE)#define TRUE (1)#endif

The constants TRUE and FALSE may only be used in assignments or in return value. Theusage as relational operand is not allowed.

Compliant Not compliant

return FALSE; return 0; /* 0 means logical FALSE */

if ( !islower(c) ){

...}

if ( islower(c) == FALSE ){

...}

Note: if possible, avoid negations, especially in compound logical expressions.

4.3 Parentheses

For readability reasons usage of parentheses in expressions is strongly recommended. Onthe other hand using too many brackets can undo the readability. So handling with due careis needed.

Deltares 19 of 54

Page 28: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

C/C++ programming rules, Technical Reference Manual

4.4 Implicit assignments

Logical expressions with ’and’ and ’or’ may not contain implicit assignments. Due to short-circuiting the evaluation, it may not be clear that the assignment will indeed take place.

Compliant Not compliant

if ( c[i] == ’ ’ && c[i+1] != ’ ’ ){

i++;...

}

if ( c[i] == ’ ’ && c[i++] != ’ ’ ){

...}

In this example the index i may not be increased if c[i] turns out not to be a space, as thesecond part of the logical expression will not be evaluated!

4.5 Conditional expressions

Using conditional expressions is strongly depreciated. It is far better to use normal if-then-elseconstructions.

Compliant Not compliant

if ( a > b ){

z = a}else{

z = b}

z = ( a > b ) ? a : b;

The conditional expression may seem very compact, but as soon as the expressions becomemore complicated, it is very difficult to see what is going on.

The following are examples of valid uses:

#define MAX(a,b) ( (a) > (b) ) ? (a) : (b) )fprintf( stderr, "Value is %s\n", ((debug_on != 0)? "true" : "false") );

The reason that these examples are allowed is that they make it possible to abbreviate con-structs without obscuring the actual intent. In the first example the use of a macro allows oneto hide the complicated structure of the conditional expression. In the second example thereis no need for an extra if-statement and a variable to hold the strings "true" and "false".1

1 Actually, even in these cases other solutions may be preferable. See chapter 7.

20 of 54 Deltares

Page 29: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

Expressions and assignments

4.6 Loop conditions

Do not misuse the expressions in a loop condition to make the body of the loop redundant.This can very easily result in unreadable code.

Compliant Not compliant

for ( p = string; *p != ’\0’; p++ ){

*p = toupper( *p);}

for ( p = string;(*p) != ’\ 0’;(*p++) = toupper(*p) );

4.7 Token pasting

Applying the so-called ’token pasting’ technique (’##’) when using macro’s is not allowed.

Compliant Not compliant

(none) #define cat(x,y) x ## y

4.8 Debug statements

Pieces of code that only become active when debugging are not allowed in production pro-grams. An example is code that gives extra debugging information when it is activated bysetting specific macros during the compilation. If it is necessary to be able to provide moredetailed information about the operation of the program, then use standardised tools (outputlogging and levels of reporting). This type of output is more useful for the user, whereas debugoutput is solely useful for the programmer.

4.9 General

To avoid common errors and uncertainties, some general requirements about statements andexpressions are formulated:

� Do not use the increment (++) and decrement (–) operators in one single expression;� Usage of the comma-operator is forbidden;� On one line only one single assignment is allowed. Both operators ’++’ and ’- -’ also are

assignments;� An actual argument may not contain an assignment. Actual arguments are arguments of

the statements if, while, switch, return, do and for. Only one exception is allowed: thewhile expression may contain one single assignment.

example:

while ( (c = fgetc(infile)) != ’\n’ )

� Using identical names for different variables in different blocks in the same function is notallowed.

Deltares 21 of 54

Page 30: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

C/C++ programming rules, Technical Reference Manual

4.10 Errors and functions

Possible errors occurring in a function must be returned by means of a function parameteror a return value. The possible values of this function parameter or return value indicate theerror that occurred.

4.11 Pointers and functions

Functions are never allowed to return a pointer to a local non-static variable, it is a severeprogramming error.

Compliant

char * IO_GetNewName ( char * nameBuffer, long sizeBuffer ){

...return nameBuffer;

}

Or, alternatively:

char * IO\_GetNewName ( void ){

static char nameBuffer[80];...return nameBuffer;

}

Not compliant

char * IO_GetNewName ( void ){

char nameBuffer[80]; ...return nameBuffer;

}

Pointers to local non-static variables are valid only as long as the routine in which the variablesare defined is active. Upon return the memory is reclaimed and such pointers become invalid.

4.12 Type casting

When data types do not correspond, explicit type casting is required. This creates clarity andtherefore increases the maintainability of programs.

Compliant Not compliant

long level;double dbl ;dbl = (double) (level * 4);dbl = (double) level * 4.0

int level;double dbl ;dbl = level * 4;dbl = level * 4.0

22 of 54 Deltares

Page 31: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

Expressions and assignments

Note: that real constants in C get the type double, unless they are suffixed with "f". Integerconstants have the type int, unless they are suffixed with "L":

Constant Type

44L4.04.0f

intlongdoublefloat

4.13 NULL pointers

Use the special symbol NULL to check if pointers are null pointers. Do not use 0, becauseNULL immediately indicates that a pointer is meant. Also do not use pointers as if they werelogical variables. Comparison to NULL must be explicit.

Pointers are often compared with NULL to determine the end of a data structure or test forvalidity. In this case the comparison has to be explicit!

Compliant Not compliant

while ( ptr != (PntrType) NULL ){

...}

while ( ptr ){

...}

Deltares 23 of 54

Page 32: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

C/C++ programming rules, Technical Reference Manual

24 of 54 Deltares

Page 33: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

5 File organisation

Source files and include files must be organised in a standard manner, to increase readabilityand maintainability of the source and include (header) files.

5.1 Source files

The organisation for source files that has been chosen for OMS has proven its usefulnessover the years and is quite common:

� The first lines contain a block of comments that describe the contents of the file and thecontext of its routines. For instance: "these routines manipulate the dictionary of keywordsas found in the OMS input files".Then come the include files:

� Standard include files, such as "stdio.h", get triangular brackets.1 They are listed first.� Program-specific include files get quotation marks.� Macros are defined next, as these are often needed in the specification of data types and

function prototypes. This is restricted to the macros that are private to the source file.More general macros and data types must be put in an appropriate header file. Do not putcomment after the macro, it might be regarded as part of the macro’s value.

� The next section is the definition of specific data types. This is of course restricted to thetypes that are private to the source file.

� Then come the global (both static and non-static) variables (sorted in alphabetic-lexicographicalorder).

� Then come the prototypes for static functions and routines in this file. Prototypes arealways required for such functions and routines, even if due to their position in the file it isnot strictly necessary.

� The last section contains the functions and routines themselves. Routines and functionsthat are not intended for use outside the source file, must be declared static. All othersmust have visible prototypes in appropriate header files.

Example (illustrating the division in sections):

/* dictionary.c - Dictionary routines

(description of the content)

*/

#include <stdio.h>#include <stdlib.h>

#include "dictionary.h"

/* Macros:INITIAL_SIZE - initial size for a dictionaryINCREMENT - amount by which to increment the array

*/#define INITIAL_SIZE 20#define INCREMENT 10

/* Data types:Cursor, CursorPtr - used to keep track of search

*/typedef struct _Cursor{

...

1There is a subtle difference between these two types of include statements. The triangular brackets arereserved for files in the standard include directories.

Deltares 25 of 54

Page 34: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

C/C++ programming rules, Technical Reference Manual

} Cursor, * CursorPtr;

/* Static functions*/static int_DictIndex( DictionaryPtr dict,

char * keyword );

/* Global variables:cursor - Cursor into the given dictionary

*/static Cursor cursor;

/* Start of actual routines and functions */

static long_DictIndex( DictionaryPtr dict,

char * keyword ){

... /* Body of routine */}

char *DictGetValue( DictionaryPtr dict,

char * keyword ){

... /* Body of routine */}

5.2 Include files

For include files the set-up is almost the same:

� The first lines contain a block of comments that describe the contents of the file and thecontext of its routines. For instance: "these routines manipulate the dictionary of keywordsas found in the OMS input files".

� Then come the include files.� Macros are defined next.� The definitions of specific data types follow.� Then come the global (both static and non-static) variables.� Finally the prototypes for public functions are given.� The last section contains the routines themselves.

To prevent problems with multiple inclusions the whole content is enclosed by an #ifndefconstruction:

#ifndef FILENAME_H_INCLUDED#define FILENAME_H_INCLUDED

/* Body of include file */

#endif /* FILENAME_H_INCLUDED */

Note: The macro used to indicate this inclusion always has the above form (replace FILE-NAME by the actual name in capitals).

example:

/* dictionary.h - Header file for dictionary routines(description of the content)

26 of 54 Deltares

Page 35: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

File organisation

*/#ifndef DICTIONARY_H_INCLUDED#define DICTIONARY_H_INCLUDED

#include <stdio.h>#include <stdlib.h>

/* Macros:NOT_FOUND - return value to indicate the keyword was not found

*/#define NOT_FOUND (char *)NULL

/* Data types:Dictionary, DictionaryPtr - the structure to hold a dictionary

*/typedef struct _Dictionary{

...} Dictionary, * DictionaryPtr;

/* Global variables:None

*/

/* Public functions

*/char *DictGetValue(

DictionaryPtr dict,char * keyword );

#endif /* DICTIONARY_H_INCLUDED */

The following additional rules must be adhered to:

� All routines and functions must have an explicit type. Thus the following declaration isforbidden:

/* Type "int" is implicit */static _DictIndex( DictionaryPtr dict, char *keyword );

� The include files must be arranged such that all routines and functions have an explicitprototype before they are first used or defined.

� If a routine or function is supposed to be available outside the source file, then its prototypemust appear in an include file.

� If a routine or function is not supposed to be available outside the source file, then it mustbe declared static and its prototype must appear in the source file.

� All prototypes for routines and functions in a particular source file must appear in the sameinclude file.

� There can be more than one routine or function in a source file, but one should keepthe total number of lines within limits and the routines and functions must be related, forinstance, all routines and function that manipulate a particular data type.

See the recommendations (chapter 7) for further remarks about names for routines and func-tions and the names of source and include files.

Deltares 27 of 54

Page 36: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

C/C++ programming rules, Technical Reference Manual

28 of 54 Deltares

Page 37: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

6 Layout, internal documentation

In this standard documentation means the complete information to be obtained from the userdocumentation, source files and the system documentation. The user documentation containsall information important to the user. The source files and the system documentation containall additional information important to the maintenance programmer. The emphasis is put onthe documentation (comments) in the source files - the system documentation will provideadditional information only. Good documentation of the source code is important for programmaintenance. A quick and correct understanding of the program text leads to quick and correctimprovements and additions.

This chapter is limited to the layout of and the documentation within the program text.

6.1 Naming conventions

A good understanding of a program text is important. Therefore clear naming conventions forthe identifiers are required:

� constants� variables� types� macros� functions

The following general conventions apply:

� The names have to be consistent, in other words: for the same meaning the same namehas to be used. (For the use of acronyms see chapter 7.)

� The names of identifiers can be up to 31 significant characters. So use descriptive names!

6.2 Language

All comments and other documentation have to be written in English without any exceptions.

6.3 Order of program text parts

For some parts of the program text the use of ordering rules is obligatory. Conforming strictlyto this ordering prevents many possible errors and makes it easier to find definitions.

The strict order of program text parts of a header file (.h) is:

� file header comment block with:� file name� programmer name� version number, date and description� copyright� file description� includes� standard files� project files� defines� constants� macro’s� enums and typedefs

Deltares 29 of 54

Page 38: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

C/C++ programming rules, Technical Reference Manual

� enums� typedefs� external variable declarations� external function prototypes

The required order of program text parts of a program file (.c) is:

� file comment header block with� file name� programmer name� version number, date and description.� copyright� file description� keywords� includes� standard files� project files� defines� constants� macros� enums and typedefs� enums� typedefs� external variable definitions(are declared in header files)� internal variable definitions( static variables)� static function prototypes(external function prototypes are placed in header files)� function definitions (global and local)� for every function:� function comment header block with:� function name� function description� summary� function heading (type, name, parameterlist)� function body

6.4 Comment

To explain the functioning of a program, the program text has to be clear enough. This canbe achieved by adding comment text to the program text. The language of the comments isalways English.

Comment headers (the first line of a comment block) start with a slash (’/’) at the first positionfollowed by between 40 and 80 asterisks (’*’). Every continuing line (except the last line) startswith an asterisk on the first position. The last line starts with between 40 and 80 asterisks,followed with a slash.

Comments consisting of only one single line must be indented according to the surroundingprogram text. Comments of more than one line may start at the left margin in order to makeuse of the full line.

Global comment preferably is placed before the function itself and detailed comment withinthe function. Detailed comment blocks of more than 10 lines are preferably placed before thefunction or else directly at the beginning of the function. The reason for this is to prevent largepieces of comment statements that decrease the readability of the actual program text.

30 of 54 Deltares

Page 39: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

Layout, internal documentation

Short comment (comment behind program statements) may only be used provided that read-ability not decreases.

——————————————————————————-

6.5 Alignment of declarations

Consecutive declarations in the program text have to be aligned with each other. In case ofpointer declarations the type-specifier is separated from the pointer (one of more ’*’) by oneor more spaces, whereas the pointer and identifier may be separated by one of more spaces.

Examples:

long cntr;char * string;char opt;char ** pString;

6.6 Statements

Only one statement per line is allowed. Statements should be consistently indented accordingto the extended style.

Example:

if ( a > b ){

z = a;y = b;

}

6.7 Assignments and expressions

Around an assignment-sign (’=’) spaces have to be placed. In expressions also spaces mustbe used. However it is recommended not to use spaces with sub-expressions.

In order to clarify the sequence of evaluation of sub-expressions brackets must be used con-sistently.

Example:

q2r = d / 2.0;area = M_PI * ( r*r ); /* M_PI is used from math.h */c = sqrt( a*a + b*b );V0 = j0(M_E/t1) * (t1 - t0); /* M_E is used from math.h */

6.8 Letters

Small letters as well as capitals may be used in program text and comment lines.

6.9 Line length

Not more than 80 characters per line may be used. There are no exceptions. The reasonis that printers normally allow only 80 characters. Longer lines would either be wrapped ortruncated.

Deltares 31 of 54

Page 40: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

C/C++ programming rules, Technical Reference Manual

6.10 File length

The length of a C source file may not exceed 3000 lines (all kind of lines). This is an absolutemaximum. Strongly recommended is a maximum of 1500 lines. Exceeding the limit of 1500lines is only permitted after consulting and getting permission from the maintenance team.

6.11 Function length

The length of a function may not exceed 300 lines (all kinds of lines). This is an absolutemaximum. Strongly recommended is a maximum of 150 lines. Exceeding the limit of 150lines is only permitted after consulting and getting permission of the maintenance team.

Note: Besides the above mentioned limits the requirements of readability, easy reference,being structured, modularity and cohesion of functions stay into effect.

6.12 Spaces

Spaces should be used to increase readability.

Compliant Not compliant

ind = 0;for (i = 0; i < 4; i++ ){

sum += c1[i+ind] + 4*i;ind += 40;

}

ind=0;for (i=0; i<4; i++){

sum+=c1[i+ind]+4*i;ind+=40;

}

recalc_xyz( t, v, &x, &y, &z); recalc_xyz(t,v,&x,&y,&z);

recalc_xyx ( t, min(v,w), &x, &y, &z);recalc_xyx (t ,min(v,w),&x,&y , &z);

Note:

� Using spaces in function calls is also clarifying:� Don’t exaggerate the use of spaces. In the last example, the spaces around ’v’ and ’w’ are

left out for readability reasons.

6.13 Braces

Braces have to be used in combination with the if, for, while and do statement, even if onlyone command is involved.

Both braces have to be placed straight above each other and directly beneath the relatedstatement.

32 of 54 Deltares

Page 41: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

Layout, internal documentation

Example:

if (a > b){

a = b;}

6.14 Indentation

From a readability point of view it is important to have a clear structure of the program text.This structure must be achieved by indentations in case of nesting. Nesting one single levelmust be accompanied by an indentation of 3 spaces. Indentations may not be achieved byusing tab characters.

Also use indentation in case of a function call which consists of more than one line.

6.15 Empty lines

To introduce logical separations in the program code extra empty lines can be used. Forexample two new lines before a function definition or one new line in block structures.

6.16 Fileheader

All C program files (.c, .h files) need to have a so-called file header block. For some simpleexamples also see the paragraph "Examples".

Every C-file must contain at least the following descriptions:

� The version information of the file. If possible this version information can be filled inby some version control mechanism. See also paragraph "Version information" in thischapter;

� The copyright information. This must be placed in the copyright comment block;� A description of the connection of the functions in the file. This means:� which common functionality do these functions have;� how these functions communicate with each other (allocate/free memory, open, read,

close);� which data structure is common for these functions;� which part or layer of a system these functions are part of.

This description must be made in the file description comment block.

These descriptions need to be in the top of the C-file in the same order.

6.17 Function header

All functions must have a so-called function header block. For some simple examples alsosee the paragraph "Examples".

All functions must contain the following items:

� The function target. This means:

� what is the use of the function;� in which cases the function can be used.� This part has to be put in the function description comment block. The function de-

Deltares 33 of 54

Page 42: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

C/C++ programming rules, Technical Reference Manual

scription in this block consists of a maximum of two lines preceded and followed byone empty line.

� How to use the function. This means:

� which part of the software is responsible for the proper input of the function (pre con-dition). See also the paragraph "Parameter" in this chapter;

� which software part is responsible for allocated memory;� which function has to be called before this function or which function has to be called

after this function;� what is the return value of this function.� This description must be placed in the function description comment block.� Which files will be approached in this function. Only the files given in full names are

meant. This description has to be put in the file i/o comment block. This commentblock is optional.

These descriptions need to be in the top of the h-file in the same order.

6.18 Functions and parameters

In this paragraph some documentation aspects of functions and parameters are described.

Functions

When defining the function a description of the return value has to be given after the functionheading (type and name).

Example:

longifac ( /* return value: faculty of integer number */

long inum) /* I integer number */...

}

Parameters

Of each function parameter the following aspects must be described:

� Whether it is an input and/or and output parameterOutput parameters optionally must havea description whether memory will be allocated and if the calling function is responsiblefor the freeing of this memory.

� The meaning of the parameter.This part can be skipped in case acronyms are used. Fora description of the use of acronyms, see chapter 7.

� The possible range of the parameter. For example, this can be a list of possible values, aminimum or a maximum value.

All above-mentioned descriptions must be on the same line at the right of the definition.

6.19 Variable/constant

Like parameters, after each definition of variable or constant the meaning has to be described.

The description must be on the same line at right of the definition.

34 of 54 Deltares

Page 43: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

Layout, internal documentation

6.20 Version information

The version information lines, also mentioned in the paragraph "Fileheader" of this chapterconsists of the following parts:

� version number - a number which increases with every change;� date - the date the change was performed in format dd-mmm-yyyy;� programmer - the initials of the person who performed the last update.

Because of the fixed format of these version lines an automatic check can be done. The checkconsists among other things of correct increase of the version number or a check whether a(proper) problem or project identification is given.

Deltares 35 of 54

Page 44: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

C/C++ programming rules, Technical Reference Manual

36 of 54 Deltares

Page 45: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

7 Recommendations

Portability library� Define a function to compose directory and file name (mkfilename())� Define a function strdup() if necessary� Define wrappers for common routines like fopen() that are bound to require checking.� Define a PATH_MAX macro, if not defined in the standard include file "limits.h"� Define TRUE and FALSE as respectively 1 and 0. Check that these values are used if

already defined� Define UNDEFINED_NAME as "–Undefined–"� Define a set of routines for logging error messages� Define a macro INVALID_STATE that prints a mesage to stderr about the program being

in an impossible or invalid state.� Define a macro ON_DEBUG like this:

#define ON_DEBUG( level, code ) \if ( _DebugLevel( level ) { code }

This macro uses a function _DebugLevel to decide if debug output is required (given thelevel), and if it is, then execute the given code. It is a flexible alternative to the codefragment presented at the end of section 2.7.

� Define macros MAX() and MIN() (functions are not possible because we would need todistinguish between types)

� Define a function BooleanString() that returns "true" or "false" given the value of its (boolean)argument. This makes the ?: construct in section 4.5 superfluous.

Data types:� Restrict the use of unsigned integers� Always use long integer (at least: do not try to be smart about short/int/long to save a few

bytes)� If you have to use << and >>, always on unsigned variables (only allowed when con-

structing bitmasks?)� Restrict the use of unions, hardly ever necessary.� Bitmasks should only be used "symbolically"� Know when to use size_t and sizeof()

Logical expressions:� Use 0 == x instead of x == 0 (if == is typed as =, the first gives a compiler error!)

7.1 Source and include files

There are no generally valid rules for the arrangement of source and include files. In thissection we present two possible solutions:

� Have pairs of source and include files� Have a limited number of include files that serve for several source files at once.

Deltares 37 of 54

Page 46: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

C/C++ programming rules, Technical Reference Manual

The first solution would involve:� Prototypes and such for a source file a.c are put in an include file a.h� Any source file depending on routines and functions in file a.c will include the file a.h.� There are no include files that include other include files (so no global include file).

The advantages of this approach are that changes in an include file only affect the sourcefiles that really use the routines and functions it declares. The disadvantage is that the list ofinclude files in the top part of each source file can become very long and unmanageable. Alsothe number of files to maintain is twice the number of source files. This is especially annoyingif the routines are rearranged in other source files. What is more, the programmer will have toknow which file defines which routine.

The second solution would involve:� Prototypes and such for several source files, a.c, b.c, c.c, d.c are put in an include file

abcd.h� Any source file depending on routines and functions in files a.c, b.c, c.c or d.c will include

the file abcd.h.� There can be an include file that include other include files.

The advantages are that the list of include files will be short. The total number of files willbe only slightly larger than the number of source files. The disadvantage is that changes inprototypes for routines found in a.c for instance, also affect files that include abcd.h but do notuse these routines.

Our recommendation is the latter (see also chapter 10), as this seems more manageableand allows header files for libraries rather than for individual source files. That is, define oneheader file per library.

7.2 Names of routines and functions

Our recommendation is to use a common prefix for the names of functions and routines thathave a common task, e.g. the routines and functions in a particular library or the routines andfunctions that manipulate a certain data structure.

The names of routines and functions must start with a capital if they are publicly useable,otherwise they should have a name starting with a single underscore and then the sameprefix. (Further refinements are possible but not desirable).

For example:The routines and function that manipulate a general hash table structure arefound in two source files, hash1.c and hash2.c, because of the total size of the routines. Thenthe following prefixes are available:

� Hash Any publicly useful routine or function� _Hash Private (both static and non-static) routines in hash1.c or hash2.c.� These routines may also be used in the other source file but are not meant for use beyond

the hash module. Via the underscore it is indicated that the non-static routines are notmeant for use outside this collection.

In all cases: The names of routines and functions must indicate their proper use. Therefore:

� Use verbs that indicate the action� Use forms like "Is" or "Has" to indicate that something is available or of the mentioned

38 of 54 Deltares

Page 47: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

Recommendations

type.

These are examples of bad names:

/* Bad: returns a string, suggests a boolean */char *DictIsAvailable( dict, keyword );

/* Bad: what does activate mean? */void DictActivateKeyword( dict, keyword, value );

Better names and declarations:

/* Good: returns a boolean, as suggested by the name */typedef long bool;bool DictIsAvailable( dict, keyword );

/* Good: store the key-value pair */void DictStoreKeyValue( dict, keyword, value );

Deltares 39 of 54

Page 48: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

C/C++ programming rules, Technical Reference Manual

40 of 54 Deltares

Page 49: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

8 Prohibited statements and constructions

8.1 Forbidden data types

Forbidden data types are:

� Bit fields and register variables

8.2 Null statement

The null statement (’;’), mostly found with for- and while-loops may not be used.

8.3 Forbidden standard functions

The standard C library contains a number of functions whose proper use is problematic orthat cause confusion. The table below lists these functions.

Function Reason for forbidding their use

I/O functionsfgetc() Unnecessary, the more useful alternative is fgets()fputc() Unnecessary, the more useful alternative is fputs()fscanf() It is near to impossible to get the end-of-line problem solved, use a

combination of fgets() and sscanf()scanf() Ditto (Use fgets() and sscanf() instead)gets() It is impossible to control the length of the string to be read, very

long input lines will cause a memory overflow. Use fgets() instead.

Miscellaneoussignal() The semantics of signals is very difficult. Their use is in the majority

of cases not necessary anyway.setjmp()longjmp()

These routines cause a non-local jump and therefore lead to un-manageable program control flows.

abort() When aborting the program, files are not properly closed .atexit() Registering call-backs is an unnecessary complication in most pro-

grams.atabort() Ditto

8.4 Illegal use of pre-processor constructs

Sometimes programmers use the pre-processor to hide C syntax or to hide fragments of codethat are only needed during testing or debugging. This is utterly forbidden. Other program-mers are not familiar with such replacements and get confused. This happens especially ifyou use macros to hide the looping over certain variables (this is an actual example of howsource code becomes almost unmanageable!)

This horror has been illustrated below (note that the hidden variable "listp" becomes visiblewhenever you want to do something with the elements of the list):

/* Define list variable here (used in macro below) */ListPtr listp;

/* Define shorthand for iteration over list */#define ScanList( list ) \

Deltares 41 of 54

Page 50: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

C/C++ programming rules, Technical Reference Manual

for ( listp = list; listp != NULL; \listp = listp->next )

int main( int argc, char *argv[] ){

.../* Scan the list of titles, searching for the right value */ScanList( titles ){

if ( strcmp( listp->value, which_title ) == 0 ){

printf( "Found it!\n" );}

}

A trivial example that attempts to introduce extra keywords (Pascal, Fortran, . . . ) into C is this:

/* DO NOT USE THE PREPROCESSOR IN THIS WAY */#define BEGIN {#define END }

if ( x > 0 ) BEGIN/* Do something */

END

There is no recommended alternative: always use the proper C syntax.

A similarly forbidden construct is this "function" that may be used to define debugging state-ments:

/* DO NOT USE THE PREPROCESSOR IN THIS WAY */#define ON_DEBUG( a ) if ( _debug_ ) { a }

Instead simply use the if-construct directly :

if ( _debug_ ){

/* Debug code */}

Yet another example:

/* DO NOT USE THE PREPROCESSOR IN THIS WAY */#if defined( DEBUG )printf( "Debug output: x = %d\n", x );#endif

The alternative here is the same as above: use a proper if-construct. The code will alwaysbe compiled, yet there is little or no impact on the performance if it is not used, because thecontrolling parameter is false.

Note: The only exception to the rule of not hiding code constructions in macros is the stan-dard assert() macro. Using this macro is actually encouraged, to document the preconditionsand post-conditions of a function.

42 of 54 Deltares

Page 51: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

Prohibited statements and constructions

8.5 Illegal use of functions

Certain standard functions are frequently used in manners that cause confusion to the reader.This section clarifies at least a number of such illegal uses.

� Functions that return integers or pointers are used in a logical contextOne example of thisis strcmp() in the following fragment:

Compliant

if ( 0 != strcmp( string1, string2 ){

fprintf( stderr, "String does not match\n" );}

Not compliant

if ( strcmp( string1, string2 ) ){

fprintf( stderr, "String does not match\n" );}

The problem is that strcmp() return 0, -1 or 1, so not a logical value at all and that the check issupposed to be "is string1 equal to string2? If not, return an error". Because strcmp() returnsa zero (ordinarily a false value) when the two strings are equal, the form of the above fragmentis as if the strings have to be equal for the error message to be printed. This is confusing.

Example:

Deltares 43 of 54

Page 52: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

C/C++ programming rules, Technical Reference Manual

Compliant

infile = fopen( "input.dat","r");if ( infile != NULL ){

fgets( ...);}else{

fprintf( stderr, "Could not open file!\n" );}

Not compliant

infile = fopen( "input.dat","r");if ( !infile ){

fgets( ...);}else{

fprintf( stderr, "Could not open file!\n" );}

44 of 54 Deltares

Page 53: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

References

Hatton, Les (1995). Safer C, Developing Software for Hingh-intergrity and Safety-critical Sys-tems. McGraw-Hill.

Kernighan, B. W. and Ritchie D. M. (1988). The C Programming Language. second edition.Prentice-Hall.

Kernighan, B. W. and R. Pike (1999). The Practice of Programming. Addison-Wesley. ISBN:0-201-61586-X.

Deltares 45 of 54

Page 54: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

C/C++ programming rules, Technical Reference Manual

46 of 54 Deltares

Page 55: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

A Set/get functions

This appendix illustrates the use of specialised pre-processor macros to elegantly solve amaintenance problem. The problem was that a set of Fortran routines needed access to datastored in a C structure, both to set the fields and to get the current value.

By defining a large number of individual get and set routines, this can be solved in a straight-forward manner. However: There were at least 30 fields involved, so this solution wouldrequire 60 individual set/get functions. If the underlying structure changed, one would need tocreate new get and set functions or update the existing ones. Therefore a solution was soughtand found in the following way (details have been left to clarify the solution): A generic setof macros was defined, one for each type of data items The fields to be accessed formed anargument to these macros The macros were embedded in a routine that could be called fromFortran where one of the arguments is the name of the field (so a string!).

From the Fortran side, one can set a field "noparams" as:

call setpar( ’noparams’, noparams )

On the C side the code that is executed looks like this (*value because Fortran passes every-thing by reference):

void setpar( char *field_name, long *value ){

...if ( strcmp( field_name, "noparams" ) == 0 ){

data->noparams = *value;}...

}

The if-construction is repeated for all relevant fields, but actually this is done via the followingmacro:

#define INT_VALUE( field ) \if ( strcmp( field_name, #field ) == 0 ) \{ \

data->field = *value; \}

So, the C routine "setpar" can actually look like this:

void setpar( char *field_name, long *value ){

...INT_VALUE( noparams )INT_VALUE( intopt )INT_VALUE( nosubst )...

}

Deltares 47 of 54

Page 56: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

C/C++ programming rules, Technical Reference Manual

48 of 54 Deltares

Page 57: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

B Examples

B.1 Example C module (.c)

/********************************************************************** Filename owndef.c

* Programmer H.Hanzon

* Version 1.00 27-11-1994 First Edition

** COPYRIGHT

** Copyright (c) 1994 "Rijkswaterstaat"

* Permission to copy or distribute this software or documentation

* in hard copy or soft copy granted only by written license

* obtained from "Rijkswaterstaat".

* All rights reserved. No part of this publication may be

* reproduced, stored in a retrieval system (e.g., in memory, disk,

* or core) or be transmitted by any means, electronic, mechanical,

* photocopy, recording, or otherwise, without written permission

* from the publisher.

************************************************************************ FILE DESCRIPTION

** This file (module) contains functions to manage the traffic at a

* crossing.

** Warning!

* This example is for clarification purposes only.

* Each definition and declaration stands for itself.

* Together, they do not form a coherent program structure.

**********************************************************************

/* ----- includes ----- */

#include <stdio.h>#include <math.h>

#include "owndef.h"

/* ----- definitions ----- */

/* traffic lights */#define RED 1 /* red light */#define ORANGE 2 /* orange light */#define GREEN 3 /* green light */#define BLINKING_ORANGE 10 /* warning light */

#define MACRO (bWhat,iThis,iThat) ((bWhat)?(iThis):(iThat))/* conditional expression */

/* ----- enums and typedefs ----- */

enum hallo{

Here,There

}; /* enumeration (example) */

typedef struct complex{

float fRe; /* real part of complex number */

Deltares 49 of 54

Page 58: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

C/C++ programming rules, Technical Reference Manual

float fIm; /* imaginary part of complex number */} COMPLEX;

typedef char *WHY;

/* ----- external variable definitions ----- */ /* afgeraden */

WHY sMe="?"; /* global variable question mark */

/* ----- internal variable definitions -----*/

static float fHome; /* internal variable (automatically initialised) */

/* ----- static function prototypes ----- */

static long ChangeState ( /* return value: error code */long * plState); /* o state of the light */

/* ----- function definitions ----- */

/********************************************************************** FUNCTION NAME GiveMessage

** FUNCTION DESCRIPTION

** This function produces a message, depending on the state of the traffic

* light.

** Warning: the description of the function may be long, but it should always

* start with (at most) two lines with a summary of the full description.

* These two lines are preceded and followed by at least one blank line.

**********************************************************************

void GiveMessage ( /* no return value */long lState, /* i state: state of the light */long iClone, /* i clone of object */float fTarget) /* i thing to hit */

{long * piPointer = &iClone; /* pointer to object */float * pfToTarget = NULL; /* pointer to target */char * sMessage = sMe; /* pointer to message */

switch (lState){case RED: /* the light is red */

printf ("stop\n");break;

case ORANGE: /* the light is orange */printf ("can you make it? then go, else stop/n");break;

case GREEN: /* the light is green */printf ("go on\n");break;

default: /* something’s wrong */printf ("watch out\n");break;

}}

/*********************************************************************

50 of 54 Deltares

Page 59: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

Examples

* FUNCTION NAME ChangeState

** FUNCTION DESCRIPTION

** This function changes the state of the light, depending on the incoming

* (current) state.

**********************************************************************

static int ChangeState ( /* return value: error code */long * plState) /* o state of the light */

{long iReturnValue = 1; /* return value */

switch (*plState){case RED: /* make it green */

*plState = GREEN;break;

case ORANGE: /* make it red */

*plState = RED;break;

case GREEN: /* make it orange */

*plState = ORANGE;break;

default: /* make it blinking */

*plState = BLINKING_ORANGE;break;

}

if (*plState == BLINKING\_ORANGE){

iReturnValue = 1; /* error */}else{

iReturnValue = 0; /* ok */}return iReturnValue;

}

B.2 Example C header file (.h)

/********************************************************************** Filename h_exampl.h

* Programmer A.L. Weg

* Version 1.00 27-11-1994 New file

** COPYRIGHT

** Copyright (c) 1994 "Rijkswaterstaat"

* Permission to copy or distribute this software or documentation

* in hard copy or soft copy granted only by written license

* obtained from "Rijkswaterstaat".

* All rights reserved. No part of this publication may be

* reproduced, stored in a retrieval system (e.g., in memory, disk,

* or core) or be transmitted by any means, electronic, mechanical,

* photocopy, recording, or otherwise, without written permission

* from the publisher.

**********************************************************************

Deltares 51 of 54

Page 60: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

C/C++ programming rules, Technical Reference Manual

** FILE DESCRIPTION

** This is my own header file

*********************************************************************/

/* ----- includes ----- */

#include <stdio.h>#include "special.h"

/* ----- defines ----- */

#define STOP 0x100 /* constant for stop */#define GO 0x200 /* constant for go */

/* ----- enums and typedefs ----- */

enum peer{

to,peer

}; /* enumeration example */

typedef union jack{

char cRed; /* example of union variable */char cWhite; /* example of union variable */char cBlue; /* example of union variable */

} JACK;

typedef long SLINGER;

/* ----- external variable declarations ----- */ /* afgeraden */

extern long iOutside; /* example of external variable */extern JACK Flash; /* example of external variable */extern SLINGER iApi; /* example of external variable */

/* ----- function prototypes ----- */

double Trouble ( /* return value: amount of trouble */long iOut); /* i control variable */

float * Boat ( /* return value: float value */long lShot); /* i control variable */

void GiveMessage ( /* no return value */long lState, /* i state: state of the light */long iClone, /* i clone of object */float fTarget); /* i thing to hit */

52 of 54 Deltares

Page 61: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

DRAFT

Page 62: C/C++ programming rules - Deltares · DRAFT Title C/C++ programming rules Client Project Reference Pages Deltares 11200568 - 54 Classification public Keywords C/C++ Summary C/C++

www.deltares.nl

DRAFT