coding.html 14.6 KB
Newer Older
Bob Halley's avatar
add    
Bob Halley committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<H2>C Language</H2>

An ANSI standard C compiler and library are assumed.  Feel free to use any
ANSI C feature.<P>

<H2>Warnings</H2>
Given a reasonable set of things to warn about (e.g. -W -Wall for gcc), the
goal is to compile with no warnings.

<H2>C Source Code</H2>

<H3>Copyright</H3>

All source files should have a copyright.  The copyright year(s)
should be kept current.  The files and the copyright year(s) should be
listed in util/copyrights.<P>

<H3>Line Formatting</H3>
<H4>Indentation</H4>
Use tabs.  Spaces are only allowed when needed to line up a continued
expression.  In the following example, spaces used for indentation are
indicated with "_":
<PRE><CODE>
	printf("this is going to be %s very long %s statement\n",
	_______"a", "printf");
</CODE></PRE>

28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<H4>Vertical Whitespace</H4>
Vertical whitespace is also encouraged for improved code legibility by
grouping closely related statements and then separating them with a
single empty line.  There should not, however, be more than one empty
adjacent line anywhere.

<H4>Line Length</H4>
Lines should not be longer than 79 characters, even if it requires
violating the indentation rules to do so.  Since ANSI is assumed, the
best way to deal with strings that extend past column 79 is to break
them into two or more sections separated from each other by a newline
and indentation:

<PRE><CODE>
        			  puts("This string got very far to the "
                                       "left and wrapped.  ANSI catenation "
                                       "rules will turn this into one
                                       "long string.");
</CODE></PRE>
Bob Halley's avatar
add    
Bob Halley committed
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82

<H3>Comments</H3>
Comments should be used anytime they improve the readability of the code.<P>

Comments may be single-line or multiline.  A single-line comment should be
at the end of the line of there is other text on the line, and should start
in the same column as other nearby end-of-line comments. The comment
should be at the same indentation level as the text it is referring to.
Multiline comments should start with "/*" on a line by itself.  Subsequent
lines should have " *" lined-up with the "*" above.  The end of the comment
should be " */" on a line by itself, again with the "*" lined-up with the
one above.  Comments should start with a capital letter and end with a
period.<P>
Good:<P>
<PRE><CODE>
	/*
	 * Private variables.
	 */

	static int		a		/* Description of 'a'. */
	static int		b		/* Description of 'b'. */
	static char *		c		/* Description of 'c'. */
</CODE></PRE>

The following lint and lint-like comments should be used where appropriate:
<PRE><CODE>
	/* ARGSUSED */
	/* FALLTHROUGH */
	/* NOTREACHED */
	/* VARARGS */
</CODE></PRE>

<H3>.h files</H3>
.h files should not rely on other files having been included.  .h
files should prevent multiple inclusion.  The OS is assumed to prevent
multiple inclusion of its .h files.<P>
83
84
85
86
87
88
89
.h files that define modules should have a structure like the
following.  Note that <isc/lang.h> should be included by any public
header file to get the ISC_LANG_BEGINDECLS and ISC_LANG_ENDDECLS
macros used so the correct name-mangling happens for function
declarations when C++ programs include the file. <isc/lang.h> should
be included for private header files or for public files that do not
declare any functions.<P>
Bob Halley's avatar
add    
Bob Halley committed
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
<PRE><CODE>
/*
 * Copyright (C) 1998  Internet Software Consortium.
 * 
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 * SOFTWARE.
 */

#ifndef ISC_WHATEVER_H
#define ISC_WHATEVER_H 1

/*****
 ***** Module Info
 *****/

/*
116
 * (Module name here.)
Bob Halley's avatar
add    
Bob Halley committed
117
 *
118
 * (One line description here.)
Bob Halley's avatar
add    
Bob Halley committed
119
 *
120
 * (Extended description and notes here.)
Bob Halley's avatar
add    
Bob Halley committed
121
122
 *
 * MP:
123
124
 *	(Information about multiprocessing considerations here, e.g. locking
 *	 requirements.)
Bob Halley's avatar
add    
Bob Halley committed
125
126
 *
 * Reliability:
127
 *	(Any reliability concerns should be mentioned here.)
Bob Halley's avatar
add    
Bob Halley committed
128
129
 *
 * Resources:
130
 *	(A rough guide to how resources are used by this module.)
Bob Halley's avatar
add    
Bob Halley committed
131
132
 *
 * Security:
133
 *	(Any security issues are discussed here.)
Bob Halley's avatar
add    
Bob Halley committed
134
135
 *
 * Standards:
136
 *	(Any standards relevant to the module are listed here.)
Bob Halley's avatar
add    
Bob Halley committed
137
138
139
140
141
142
 */

/***
 *** Imports
 ***/

143
144
/* #includes here. */
#include &lt;isc/lang.h&gt;
Bob Halley's avatar
add    
Bob Halley committed
145
146
147
148
149

/***
 *** Types
 ***/

150
/* (Type definitions here.) */
Bob Halley's avatar
add    
Bob Halley committed
151
152
153
154

/***
 *** Functions
 ***/
155
156
157
ISC_LANG_BEGINDECLS
/* (Function declarations here, with full prototypes.) */
ISC_LANG_ENDDECLS
Bob Halley's avatar
add    
Bob Halley committed
158
159
160
161
162
163
164

#endif /* ISC_WHATEVER_H */

</CODE></PRE>

<H3>C Source</H3>
<H4>Including Interfaces (.h files)</H4>
165
166
167
168
The first file to be included in a C source file must be config.h.
The config.h file must never be included by any public header file
(that is, any header file that will be installed by "make install").
Try to include only necessary files, not everything under the sun.<P>
Bob Halley's avatar
add    
Bob Halley committed
169
170
171
172
Operating-system-specific files should not be included by most modules.<P>
Include UNIX "sys" .h files before ordinary C includes.<P>

<H4>Statements</H4>
173
174
There should be at most one statement per line.  The comma operator
should not be used to form compound statements.<P>
Bob Halley's avatar
add    
Bob Halley committed
175
176
177
178
Bad:<P>
<PRE><CODE>
	if (i > 0) {
		printf("yes\n"); i = 0; j = 0;
179
                x = 4, y *= 2;
Bob Halley's avatar
add    
Bob Halley committed
180
181
	}
</CODE></PRE>
182
<H4>Functions</H4>
Bob Halley's avatar
add    
Bob Halley committed
183
184
185
186
187
188
The use of ANSI C function prototypes is required.<P>
The return type of the function should be listed on a line by itself when
specifying the implementation of the function.  The opening curly brace should
occur on the same line as the argument list, unless the argument list is
more than one line long.<P>
Good:<P>
189
<PRE><CODE>
Bob Halley's avatar
add    
Bob Halley committed
190
191
192
193
194
195
196
197
198
199
200
201
202
static inline void
f(int i) {
	/* whatever */
}

int
g(int i, /* other args here */
  int last_argument)
{
	return (i * i);
}
</CODE></PRE>

203
204
205
206
207
208
209
To suppress compiler warnings, unused function arguments are declared
using the <CODE>UNUSED()</CODE> macro.<P>

In the function body, any <CODE>REQUIRE()</CODE>s are placed
immediately after the local variabled, followed by any
<CODE>UNUSED()</CODE> declarations.<P>

210
211
<H4>Curly Braces</H4>
Curly Braces do not get their own indentation.
Bob Halley's avatar
add    
Bob Halley committed
212
213
214
215
An opening brace does not start a new line.  The statements enclosed
by the braces should not be on the same line as the opening or closing
brace.  A closing brace should be the only thing on the line, unless
it's part of an else clause.<P>
216
217
218
219
220
221
222
223

Generally speaking, when a control statement (<CODE>if, for</CODE> or
<CODE>while</CODE>) has only a single action associated with it, then no
bracing is used around the statement.  Exceptions include when the
compiler would complain about an ambiguous else clause, or when extra
bracing improves the readability (a judgement call biased toward not
having the braces).<P>

Bob Halley's avatar
add    
Bob Halley committed
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
Good:<P>
<PRE><CODE>
static void
f(int i) {
	if (i > 0) {
		printf("yes\n");
		i = 0;
	} else
		printf("no\n");
}
</CODE></PRE>
Bad:<P>
<PRE><CODE>
void f(int i)
  {
    if(i<0){i=0;printf("was negative\n");}
    if (i > 0)
      {
        printf("yes\n");
        i = 0;
      }}
</CODE></PRE>

<H4>Spaces</H4>
<UL>
249
<LI>Do put a space between operators like '=', '+', '==', etc.
Bob Halley's avatar
add    
Bob Halley committed
250
251
252
253
254
255
<LI>Do put a space after ','.
<LI>Do put a space after ';' in a 'for' statement.
<LI>Do put a space after 'return', and also parenthesize the return value.
</UL>
<UL>
<LI>Do not put a space between a variable or function name and '(' or '['.
256
257
<LI>Do not put a space after the "sizeof" operator name, and also
parenthesize its argument, as in <CODE>malloc(4 * sizeof(long))</CODE>.
Bob Halley's avatar
add    
Bob Halley committed
258
259
260
261
262
263
264
265
266
267
268
269
<LI>Do not put a space immediately after a '(' or immediately before a ')',
unless it improves readability.  The same goes for '[' and ']'.
<LI>Do not put a space before '++' or '--' when used in
post-increment/decrement mode, or after them when used in
pre-increment/decrement mode.
<LI>Do not put a space before ';' when terminating a statement or in a 'for'
statement.
<LI>Do not put a space after '*' when used to dereference a pointer, or on
either side of '->'.
<LI>Do not put a space after '~'.
<LI>The '|' operator may either have a space on both sides or it may have no
spaces.
270
<LI>Do not put a space after a cast.
Bob Halley's avatar
add    
Bob Halley committed
271
272
273
274
</UL>

<H4>Return Values</H4>
If a function returns a value, it should be cast to (void) if you don't
275
care what the value is, except for <CODE>printf</CODE><P>
Bob Halley's avatar
add    
Bob Halley committed
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317

All error conditions must be handled.<P>

Mixing of error status and valid results within a single type should be
avoided.<P>
Good:
<PRE><CODE>
	os_descriptor_t		s;
	os_result_t		result;

	result = os_socket_create(AF_INET, SOCK_STREAM, 0, &s);
	if (result != OS_R_SUCCESS) {
		/* Do something about the error. */
		return;
	}
</CODE></PRE>
Not so good:
<PRE><CODE>
	int s;

	/*
	 * Obviously using interfaces like socket() (below) is allowed
	 * since otherwise you couldn't call operating system routines; the
	 * point is not to write more interfaces like them.
	 */
	s = socket(AF_INET, SOCK_STREAM, 0);
	if (s < 0) {
		/* Do something about the error using errno. */
		return;
	}
</CODE></PRE>

<H4>Integral Types</H4>
Careful thought should be given to whether an integral type should be
signed or unsigned, and to whether a specific size is required.  "int"
should be used for generic variables (e.g. iteration counters, array
subscripts).  Other than for generic variables, if a negative value isn't
meaningful, the variable should be unsigned.  Assignments and
comparisons between signed and unsigned integers should be avoided;
suppressing the warnings with casts is not desireable.<P>

<H4>Casting</H4>
318
319
320
321
322
323
324
Casting should be avoided when possible.  When it is necessary, there
should be no space between the cast and what is being cast.<P>

Bad (obviously for more than one reason ...):
<PRE><CODE>
	(void) malloc(SMBUF);
</CODE></PRE>
Bob Halley's avatar
add    
Bob Halley committed
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411

<H4>Clear Success or Failure</H4>
A function should report success or failure, and do so accurately.  It
should never fail silently.  Use of Design by Contract can help here.<P>

<H4>Testing Bits</H4>
Bit testing should be as follows:<P>
Good:
<PRE><CODE>
	/* Test if flag set. */
	if ((flags & FOO) != 0) {

	}
	/* Test if flag clear. */
	if ((flags & BAR) == 0) {

	}
	/* Test if both flags set. */
	if ((flags & (FOO|BAR)) == (FOO|BAR)) {

	}
</CODE></PRE>
Bad:
<PRE><CODE>
	/* Test if flag set. */
	if (flags & FOO) {

	}
	/* Test if flag clear. */
	if (! (flags & BAR)) {

	}
</CODE></PRE>

<H4>Pointers</H4>
<H5>Null Pointer</H5>
The null pointer value should be referred to with "NULL", not with "0".
Testing to see whether a pointer is NULL should be explicit.<P>
Good:
<PRE><CODE>
	char *c = NULL;

	/* ... */

	if (c == NULL) {
		/* Do something. */
	}
</CODE></PRE>

<H5>Invalidating Pointers</H5>
When the data a pointer points to has been freed, or is otherwise no longer
valid, the pointer should be set to NULL unless the pointer is part of a
structure which is itself going to be freed immediately.<P>
Good:
<PRE><CODE>
	char *text;

	/* text is initalized here. */

	free(text);
	text = NULL;
</CODE></PRE>

<H4>Testing for Zero or Non-zero</H4>
Explicit testing against zero is required for numeric, non-boolean variables.
<P>
Good:
<PRE><CODE>
	int i = 10;

	/* ... */

	if (i != 0) {
		/* Do something. */
	}
</CODE></PRE>
Bad:
<PRE><CODE>
	int i = 10;

	/* ... */

	if (i) {
		/* Do something. */
	}
</CODE></PRE>

412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
<H4>The Ternary Operator</H4>
The ?: operator should mostly be avoided.  It is tolerated when
deciding what value to pass as a parameter to a function, such as 
frequently happens with printf, and also when a simple (non-compound)
value is being used in assignment or as part of a calculation.
In particular, using the ternary operator to specify a return value is
verboten.<P>

Good:
<PRE><CODE>
	printf("%c is%s a number.\n", c, isdigit(c) ? "" " NOT");
        l = (l1 < l2) ? l1 : l2;
        if (gp.length + (go < 16384 ? 2 : 3) >= name->length) {
           ...
        }
</CODE></PRE>

Bad:
<PRE><CODE>
	return (success ? ISC_R_SUCESS : ISC_R_FAILURE);
</CODE></PRE>

<H4>Assignment in Parameters</H4>
Variables should not have their values assigned or changed when being
passed as parameters, except perhaps for the increment and decrement
operators.<P>

Bad:
<PRE><CODE>
	malloc(size = 20);
</CODE></PRE>

Ok:
<PRE><CODE>
	fputc(c++, stdout);
</CODE></PRE>

<H3>Namespace</H3>
<H4>Public Interfaces</H4>
All public interfaces to functions, macros, typedefs, and
variables provided by the library, should use names of the form
{library}_{module}_{what}, such as:
<PRE><CODE>
	isc_buffer_t				/* typedef */
        dns_name_setbuffer(name, buffer)	/* function */
        ISC_LIST_HEAD(list)			/* macro */
        isc_commandline_argument		/* variable */
</CODE></PRE>
however, structures which are typedef'd generally have the name of the
typedef sans the final _t:
<PRE><CODE>
	struct dns_rbtnode {
        	/* ... members ... */
	}
</CODE></PRE>
Generally speaking macros are defined with all capital letters, but
this is not universally consistent (eg, numerous isc_buffer_{foo}
macros).<P>
The {module} and {what} segments of the name do not have underscores
separating natural word elements, as demonstrated in
isc_commandline_argument and dns_name_setbuffer above.  The {module}
part is usually the same as the basename of the source file, but
sometimes other {module} interfaces appear within one file, such as
dns_label_* interfaces in lib/dns/name.c.  However, in the public
libraries the file name must be the same as some module interface
provided by the file; e.g., dns_rbt_* interfaces would not be declared
in a file named redblack.c (in lieu of any other dns_redblack_*
interfaces in the file).<P>

The one notable exception to this naming rule is the interfaces
provided by <isc/util.h>.  There's a large caveat associated with the
public description of this file that it is hazardous to use because it
pollutes the general namespace.<P>

<H4>Shared Private Interfaces</H4>
When a module provides an interface for internal use by other modules
in the library, it should use the same naming convention
described for the public interfaces, except {library} and {module}
are separated by a double-underscore.  This indicates that the name is
internal, its API is not as formal as the public API, and thus it
might change without any sort of notice.

Bob Halley's avatar
add    
Bob Halley committed
494
495
496
497
498
499
500
<H3>Initialization</H3>
When an object is allocated from the heap, all fields in the object must be
initialized.<P>

<H3>Dead Code Pruning</H3>
Source which becomes obsolete should be removed, not just disabled with
#if 0 ... #endif.<P>