Open Watcom C/C++ Source Code Style Guidelines

[edit]

Introduction
Open Watcom products are usually written mostly in C, but there is also a substantial body of C++ code and a small amount of assembler for various platforms. This document describes the style conventions used by Open Watcom contributors for all Open Watcom projects, and is intended to be used as a guideline if you are going to be modifying the source code in any way. Any contributed code that is to be included in a Open Watcom product must follow these style guidelines; submissions violating these guidelines will be rejected. It is important to have all source code formatted in a similar manner as this helps to give the entire product a cohesive image, and makes finding one's way around the source code much easier. Because C and C++ are entirely free-form, there are many different ways that the source code can be formatted. All programmers have their own preferred formatting style, just as all writers have their own personal writing style. However, just as when multiple authors work on a single book, multiple programmers working on a common software product should adhere to consistent formatting and style conventions. This document is intended to serve as a guide to the style guidelines used by Open Watcom developers. If, however, something is not clearly documented here, the best reference to the style guidelines is to look at some Open Watcom source code. NB: The Open Watcom code base is very large (over two million lines of C/C++ source code) and was written by many people over the period of over 20 years. As a result, not every source file conforms to these guidelines. You may wish to reformat existing non-conforming source files, but if you do so, please observe the following: it is highly recommended that you reformat an entire project or subproject instead of a single source file, and never mix formatting changes with functional changes. Always submit formatting changes separately, as it makes source code maintenance much easier. [edit]

Indentation and Tab Width
All source code should be formatted to use 4-space tabs, and all indentation should be in multiples of four spaces (one indentation level). The source code should be formatted using only real spaces and never hard tabs, so you will need to configure your editor to use 4 space tabs and to insert spaces only into the source code. Do NOT use 8-space hard tabs in your source code! If you absolutely must work with 8space hard tabs, please run the resulting source code through a tab expansion utility. Note that this also includes assembly code. Only files that absolutely require hard tabs (notably GNU makefiles) are exempt from this rule. [edit]

Source Code Width
All source code should try to use a maximum of 80 characters per line. Some editors can only display 80 characters on a line, and using more can cause them to exhibit line wrap. This is only a guideline, and if more than 80 characters will enhance the legibility of the code, use wider source lines---but not too much wider. Lines longer than 100 characters are supect and more than 130 columns is absolutely out of the question.

[edit]

C/C++ Source Code Formatting
This section describes the conventions used for formatting C and C++ source code modules, and the conventions that you should follow if you modify or extend any of the source code. All C source code should be contained in text files with the .c extension, and all C++ source code should be contained in text files with the .cpp extension. It is highly recommended that all source file names are lowercase and following the 8.3 convention for maximum portability. Files that are not lowercase are only acceptable if there are externally imposed requirements for them; it is never allowed to have two files in the same directory whose names only differ in case. [edit]

Source File Layout
The overall layout for source code is important to help developers quickly find their way around unfamiliar source code for the first time. All C and C++ source code modules should be formatted in the following manner: /**************************************************************************** * * Open Watcom Project * * Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved. * * ======================================================================== * * This file contains Original Code and/or Modifications of Original * Code as defined in and that are subject to the Sybase Open Watcom * Public License version 1.0 (the 'License'). You may not use this file * except in compliance with the License. BY USING THIS FILE YOU AGREE TO * ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is * provided with the Original Code and Modifications, and is also * available at www.sybase.com/developer/opensource. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR * NON-INFRINGEMENT. Please see the License for the specific language * governing rights and limitations under the License. * * ======================================================================== * * Description: Description of the code module. This should describe the * purpose of the code in this module. * ****************************************************************************/

#include "myhdr.h"

/* Include any necessary headers */

/* Global variable declarations and static variables with file scope */ /* All functions implemented in this module. Where possible static or * private functions should be located before functions that use them to * avoid the need for superfluous function prototypes. However all functions * *MUST* have a prototype, so if necessary add local prototypes to the top * of the file before the regular functions begin. */ [edit]

Function Body
The body of a C or C++ function should be written with the open brace that starts the body of the function in the leftmost column, and the closing brace in the same column. All source code statements contained within the function body should start at the first indentation level (four spaces in). The name of the function and an opening '(' should be on the first line, with the return type preceding the function name. If the function is static or private, it may be left without any preceding documenation provided the function is short. However any function that contains more than about 5 lines of source code and all public functions should be preceded with a source code comment. An example of a properly formatted function with documentation header is as follows: // Concise description of the function. // May use C or C++ style comments. bool my_function( int arg1, int arg2 ) { // function body } There is no single standard for commenting functions used throughout the Open Watcom source tree. However, two common commenting styles are shown below: /* * my_function - description of the my_function function, which may span * multiple lines if necessary */ bool my_function( int arg1, int arg2 ) { // function body } /* my_function */ bool my_function( int arg1, int arg2 ) /************************************/ {

[edit] // external to module // local to module Flow Control Statements All the flow control statements should have the open brace placed on the same line as the start of the flow control statements. Recommended formatting is as follows: void my_long_function( first_complex_type *arg1. the latter that parameters are unspecified. Several projects in the source tree use capitalisation rather than underscores to separate the words. Note also that for improved legibility. When declaring a C++ function that takes no arguments or calling a function in C/C++ with no arguments there should be no space between the parenthesis (). The closing brace should be indented to be at the same level as the flow control statement keyword. the flow control statements should be formatted with a single space after the opening parenthesis and another before the closeing parenthesis. void MyFunction( void ). and all statements that are part of the body of the flow control statement should be indented by one level (four spaces). void myFunction( void ). third_complex_type *arg4 ) { // function body goes here } Note that a C language function which takes no parameters should be declared as type foo( void ) rather than type foo(). it is a good idea to use the same commenting style throughout any particular module.// function body } Generally. as well as a space before the opening brace. This helps to partition the statement into the declaration section and the body section of the statement. int arg3. second_complex_type *arg2. If a function has too many arguments to comfortably fit on a single line. In this case the first word is not capitalised for a function local to that module and is capitalised for an exteral function. the line needs to be broken up appropriately. The former says foo has no parameters. For example: if( condition ) { } rather than the less legible if(condition){ } . Continuity within a project is important.

therefore this form should be avoided. Hence if this form is used.  placed on the same line if( condition ) consequence.Where the dependent statement does not require braces. break or continue. [edit] If-else Statements if( x < foo ) { // do something. do so like this: if( x < foo ) { // do something. If a conditional statement is formated like if( condition ) do_something(). it is impossible to put a breakpoint on the conditional statement in a line oriented debugger. }  indented on the next line if( condition ) consequence. either:  be given braces it does not strictly require if( condition ) { consequence. it should only ever be done with control constructs such asreturn. } else { . it may be. it is not immediately obvious when stepping over the line in a debugger whether do_something() was executed or not. The following shows the templates to use for formatting each of the flow control structures in C and C++. } If you wish to use multiple if-else statements strung together. } else if( x < bar ) { // do something else. The last form is not recommended for practical reasons. } else { // do something else. in order of preference. Even so.

[edit] While Loops while( x > 1 ) { // do something. } . put braces around the nested ifelse. [edit] For Loops for( i = 0. For example: if( foo ) { if( bar ) { win(). ++i ) { // do something.// default case. } } rather than the less legible: if( foo ) if( bar ) win(). } When you have an if-else statement nested in another if-else statement. i < 10. } [edit] Do-while Loops do { // do something. } else { lose(). } while( x > 1 ). else lose().

Copied+=Copy. and there is always a single space after the semicolon.WinSize). unfortunately) is not admissible under any circumstances and may be considered a capital offence in some countries: for(RamAddr=_uldiv(__nvram.i++){ } If you wish to include multiple assignments in the opening statement of the for statement. ++i. Copy=(USHORT)min(__nvram.Note that with the for statement. i < 10. pApp=pApp+Copy) { /* loop body */ } The rule of thumb is that if the controlling statement of a for loop is longer than a single line.RamAddr. For example avoid formatting your statements like this: for(i=0. pIO->Size-=Copy.CMapTable[pIO->Selector]. j += 10 ) { } Do not try to cram too much into the controlling statement of the for loop.quot++.rem. } should be used instead of the alternative while( 1 ) { // do something in a not so nice way. However ensure that a space always follows the comma: for( i = 0.CMapShadow. ) { // do something. j = 0.pApp=(PBYTE)pIO->Data. for( . or multiple operations in the counter section of the for statement then use the comma operator. For instance the following code (not a contrived example.i<10. [edit] Switch Statements switch( x ) { .(ULONG)pIO->Size)..Offset+ pIO->Offset. there is no space before the semicolons. it is too long. } The rationale is that some compilers may warn on the latter form because the condition is always true.Copied=0U.WinSize-RamAddr.RamAddr.rem=0UL.__nvram.

case 1: // code for case 1 break; case 2: // code for case 2 break; default: // default case } case and default are viewed as part of switch for indentation purposes. If the code for the cases in the switch statement is exceptionally short, you can format the entire case on a single line, such as the following: switch( x ) { case 1: /* tiny code */; case 2: /* more code */; }

break; break;

If you wish to create a nested code block for a case statement (for example to declare some local variables in C code), do so like the following: switch( x ) { case 1: { int local_var; // code for case 1 } break; ... } It is advisable to include a default action for a switch statement, but this may be left out. If falling through is used in switch statements, a comment to that effect must be added, such as this: switch( x ) { case 1: // code for case 1 /* fall through */ case 2; // code for case 2 break; default: // default case

} [edit]

Goto Statements
Occasionally, it is reasonable to use goto statements. The corresponding labels should be indented to the same level as the braces enclosing both goto and label. switch( argv[0][1] ) { ... case 'D': if( !optionsPredefine( &argv[0][2] ) ) goto errInvalid; break; ... default: errInvalid: ... } Usage of gotos should be kept to minimum and is generally not recommended, although the objections are purely practical (difficult to understand and maintain, dangerous) and not religious. [edit]

Expressions
When formatting expressions, try to use spaces and parentheses to enhance the readability of the expression---splitting it over multiple lines if necessary to make it more readable. Do not format expressions without any spaces between binary operators and their operands. For example, write x = (y + 10) - 240 * (20 / (t + my_func())); rather than x=(y+10)-240*(20/(t+my_func())); If parentheses contain an expression, there should be no space after the opening and before the closing parenthesis. Combined with the preceding guidelines, code should be formatted this way: if( (a || my_func( b )) && ((c = my_other_func( 1 + x )) == 42) ) { // do something }

That is, for parentheses that are parts of control statements and function calls, spaces should be after the opening and before the closing parenthesis, but spaces need not be used with parentheses that simply group expressions together. The parentheses following the TEXT and _T prefixes commonly used to specify strings in Win32 code should be considered to be instances of this rule and should not have spaces around the string, even though these prefixes are implemented as macros. For example, write const TCHAR szString[] = _T("Some Text"); [edit]

Return Statements
In functions that return a value, the return expression should be placed in parentheses. For example: return( i + 1 ); or return( TRUE ); In other words, format return statements as if return was a function. [edit]

Operator sizeof
The same applies to the sizeof operator, that is, parentheses should always be used as if sizeof was a function (which it of course isn't). For example: i = sizeof( void * ); [edit]

Variable Declarations
Don't declare multiple variables in one declaration that spans lines. Instead, start a new declaration on each line. For example, instead of int foo, bar; write either this (recommended form): int foo; int bar; or, if you are lazy, this:

void const *my_ptr. { int my_var1. Global variables that are private to the source module should always be declared with static storage. // code follows here } Note that the declaration block is separated from the first statement in the function by a blank line. }. [edit] Arrays When an array is dimensioned or accessed. int my_var1. bar. my_struct my_structure = { . long my_var2. For example: void foo( void ) // 45678 1 234567 column counter for illustration..int foo. . aligning the names of the variables on tab stops is highly recommended. although it was not in earlier language revisions). For example: // 45678 1 234567 column counter for illustration. long my_var2. The register storage class specifier should not be used because nearly all compilers will ignore it. [edit] Global Variables Within a Module Any global variables and external global variables must be declared at the top of the source file. as detailed above. When formatting global variables. and the auto storage class should not be used either as it is superfluous in the presence of a type specifier (which is required by ISO C99.. the subscript should be specified with no space to the right of the left square bracket or to the left of the right square bracket. For example: int array[5]. External global variables should always be declared in a separate header file. [edit] Local Variables Declarations of local variables should be formatted similarly to those of global variables. and the definition in a single source module.

etc. } else { do_something_else(). #include. For example: void foo( int b ) { if( b > 3 ) { do_stuff(). when extern "C" { and } are placed in #ifdef __cplusplus blocks.h> #else #include <hdr3. For example: #ifdef A_SYMBOL #ifdef ANOTHER_SYMBOL #define YET_ANOTHER_SYMBOL #include <hdr1. #ifdef __NT__ do_nt_stuff().) is conditionally processed. they need not be indented. } } [edit] . #elif defined( __OS2__ ) do_os2_stuff().h> #undef A_SYMBOL #endif #endif The above only applies for source text that consists solely or chiefly of preprocessor directives. [edit] Preprocessor Directives When a series of preprocessor directives (#define. For conditional compilation of code. When conditional compilation is used to prevent duplicate inclusion of an entire header file (idempotency lock). In most cases. Also. preprocessing directives should start at the leftmost column and should not affect the indentation of actual code.do_something( array[3] ). the directives between #if or #ifdef and the corresponding #endif should indented four or two spaces.h> #endif #ifdef A_THIRD_SYMBOL #include <hdr2. #endif do_more_stuff(). the code in that header file should not be automatically indented. the rules are somewhat different.

Note that automatically generated header files usually use a . they are a form of engineering etiquette... Comments should always be used to clarify otherwise obscure code. this could be an issue when porting // to new platforms. Please refer to the section on Function Bodies for detailed information on the layout and formatting for function headers.. and how the comments should be laid out: void myFunc( void ) { int x1 = 10. The following shows examples for commented source code.gh extension.. /* Comment describing X1's purpose if necessary */ /* Open up the file and write the value X1 to it */ .haphazardly placed comments are almost as bad as haphazardly formatted source code. All C header files should be contained in a text file with the . . so we have a large block * comment that spans multiple lines. If the code itself describes concisely what is happening. Comments should also be used to document the purpose of obscure or non-trivial functions (a non-trivial function is one of more than a few lines) and what inputs and outputs the function deals with.. but be aware that not all // C compilers may accept them. comment too liberally. // One line comments may be like this ..h extension. All C header files should be formatted in the following manner: .. // C++ style comments are also allowed. [edit] Header File Layout The overall layout for header files is important to help developers quickly find their way around unfamiliar source code for the first time. [edit] C Header File Formatting This section describes the conventions used for formatting C header files. /* Now do some stuff that is complicated.. however. */ . These should be formatted as * follows for C and C++ code. and the conventions that you should follow if you modify or extend any of the source code.Comments and Commenting Style Commenting code is extremely important. do NOT provide a comment explaining the obvious! Comments should always be neat and readable . Do not. Comments serve as an aid to the human readers of source code. but those files are naturally not intended to be edited directly.

headers not intended to be built with any other * compiler) should use reserved names.sybase. Please see the License for the specific language * governing rights and limitations under the License. All Rights Reserved. You may not use this file * except in compliance with the License. BY USING THIS FILE YOU AGREE TO * ALL TERMS AND CONDITIONS OF THE LICENSE. This should describe the * purpose of this header file. declare structure packing. and is also * available at www.. * ****************************************************************************/ #ifndef HEADER_H_INCLUDED /* Include guard. AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM * ALL SUCH WARRANTIES. e. The _Packed keyword may be .. */ #include <stdio. FITNESS FOR A PARTICULAR PURPOSE.0 (the 'License'). Implementation specific * headers distributed to end-users have to use reserved names. * * ======================================================================== * * This file contains Original Code and/or Modifications of Original * Code as defined in and that are subject to the Sybase Open Watcom * Public License version 1. WITHOUT WARRANTY OF ANY KIND. Inc.g./**************************************************************************** * * Open Watcom Project * * Portions Copyright (c) 1983-2002 Sybase. ANY WARRANTIES OF * MERCHANTABILITY. A copy of the License is * provided with the Original Code and Modifications.com/developer/opensource. * * ======================================================================== * * Description: Description of the header file.h here). INCLUDING WITHOUT LIMITATION. EITHER * EXPRESS OR IMPLIED. * #endif * Only system headers (ie. QUIET ENJOYMENT OR * NON-INFRINGEMENT. The #define name should be */ #define HEADER_H_INCLUDED /* the same as the header (ie: header.h> /* Include any dependent include files */ /* If necessary. */ /* HEADER_H_INCLUDED would be in the user's "namespace". * #ifndef _STDLIB_H_INCLUDED * #define _STDLIB_H_INCLUDED * . * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis.

The format for defining an enumeration typedef is as follows: typedef enum { CHANGE_NORMAL CHANGE_ALL CHANGE_GEN CHANGE_CHECK } change_type.* used on individual basis instead of the #pragma. so that the structure can be used without requiring the struct or union keyword. 0x04 Structures and Unions It is preferred to declare structures and unions using a typedef. */ #ifdef __cplusplus extern "C" { /* Use "C" linkage when in C++ mode */ #endif /* Include C function prototypes in here */ #ifdef } #endif #endif [edit] __cplusplus /* End of "C" linkage for C++ */ /* HEADER_H_INCLUDED */ Enumerations Enumerations should be defined for all numerical constants used in header files. structures and unions should be * defined in this section for both C and C++ code. 0x01. For example: . */ #pragma pack( push. type definitions. and perhaps more importantly. 1 ) /* Macros. 0x02. enumerations. The reason for this is that it provides a logical grouping for related constants. */ /* Restore the previous packing value if it has been changed */ #pragma pack( pop ) /* The following is not stricly required for header files that are * never to be included from C++ code. [edit] = = = = 0x00. rather than using a macro #define or a set of constants. eases debugging (because the debugger knows about enumerations but doesn't know about macros).

int arg2. For instance a couple of prototypes might declared as follows: extern bool my_function( int arg1. For C callable functions (even if implemented in C++) the function prototypes must be bracketed with extern "C" as shown in the sample header file above. rather than: struct score_reg { }. and having a single function per line makes it easy to browse header files to find a specific function prototype. For example: // 45678 1 2345678 2 2345678 extern int my_var1.. the C/C++ compiler will do the necessary job of checking that the parameters in the prototype are correct with respect to the function body. Each public function should be declared on a single line. } score_reg. [edit] Function Prototypes All public functions must be declared in only one header file. int arg2 ). } symbol. typedef union { . union symbol { }. This is to ensure that all global functions will be callable from both C and C++ code. [edit] Global Variables Any public global variables must be declared in a header file. format them so that the names of the variables align on tab stops. .. For C++ code however.. int arg3 ). When formatting global variable declarations. Although it may seem strange to format functions prototypes in this manner. Note also that this is one case where you must violate the 80 characters per line guideline and not break the function prototype across multiple lines. in the 'function prototypes' section of the header file. since the language treats these constructs differently. you should declare structures and unions without using the typedef keyword. extern my_structure *my_function2( int arg1.typedef struct { ..

etc should have their names aligned so differences and simiularities can be seen more easily.just same layout as C header file layout? [edit] Namespaces    Always comment the close of a namespace Indentation TBD Standard names used for OW extentions and OW internals TBD namespace std{ } // namespace std [edit] Classes TBD . Various bits will need to be filled in as we come to a consesus. please place the body of the function after the class definition in the same header file. For inline functions that are more than about 2 lines long. C++ Specific Formatting This is WIP. logically related classes such as a node class and the list class that uses the nodes. . // Describe what this is for // Comment for the function virtual void myProtectedFunction(). typedefs.ditto for member functions? Blocks of related member fuctions. It may be more convenient in some instances to place multiple class definitions into a single header file. for example. small. If it defined by a standard it should follow the ordering in the standard as closely as posible. my_structure. For small inline functions. class MyClass : public Base { protected: int myVar. *my_pointer. [edit] Header File Layout TBD .should non-standard classes be written TheClass or the_class? TBD .extern ulong extern score_reg extern long [edit] my_var2. place the function body within the class declaration. The class should be ordered TBD. Generally try to place a single class definition into a single header file.

inline void largeInlineFunction() { // first line of function // second line of function }. end(). [edit] Templates The parameter list for a template should be formatted. .. It is also consistent with the way functions are formatted according to this guide. int n ). // align related funtions to highlight differences and simularities void insert( int value. inline void reallLargeInlineFunction(). int n ). }. iterator const_iterator iterator const_iterator begin(). inline void smallInlineFunction() { // function body. }. friend void myPublicFriend(). end() const. // Always document virtual functions virtual void myPublicVirtual(). inline void mediumInlineFunction() { // function body. if possible. It is recommended that a space be placed immediately after the opening '<' and immediately before the closing '>'. entirely on a single line.public: // constructors and destructor first MyClass().. // body is defined outside of class }. template< class T. This makes it less likely that the unexpected tokens will be produced (particularly '>>' or '<:'). bool remove( int value ). class U > class MyClass { . long_type insert( const char *str. begin() const. ~MyClass().

TBD put example of it here [edit] .. An example is shown below. size_type pos. This is mainly due to the amount of time needed to read some C++ template member functions. class ALongTypeParameter. Usually template functions and member function definitions should be formated simularly to normal functions: template< class Type.. } template< class InputIterator. template< class T. const AnotherType &a ) { . AnotherType >::function( const int i. } [edit] Function Headers In my opinion there is a need for some sort of function header comment. class AnotherType = WithDefault< T > > complicated_template< T. AnotherType >::return_type complicated_template< T. InputIterator last. Allocator >::swap( list &other ) { . class Function > Function for_each( InputIterator first. } It is probably best to avoid unnecessarily long parameter names but if the list is long a split will be necessary. S.. ALongTypeParameter.}. Function f ) { .. class S.... ALongTypeParameter. S. Return types can get very long and in this case should be put on a separate line. S &s. class Allocator > void list< Type.

therefore should be used. and many. or the library for some reason cannot be used. but an alternate codepath needs to be provided for other compilers and/or platforms. [edit] Compiler Extensions In general. In some cases (eg. ISO C should be used wherever possible. In the extremely rare cases where that might not be possible. Portable POSIX interfaces should be used where ISO C is insufficient (and to the extent that the POSIX functionality is supported by Open Watcom on all platforms). Some of these are discussed in greater detail below. [edit] Adherence to Standards Programs should be written to comply with the most general standard that provides desired functionality. Platform specific APIs should only be used as a last resort. In cases where the use of an extension (such as #pragma aux) can substantially improve otherwise portable code. there are three file I/O models available:    Standard C library streams POSIX style file handle based I/O Win32 API calls For most purposes. Reducing the warning level is out of the question and explicitly disabling warnings is frowned upon. [edit] Don't Assume Don't make too many assumptions about the language or environment. byte order. code should be written with minimal reliance on compiler extensions as long as it is intended to be portable. This means that for instance the C compiler itself should be written in a portable manner. the DOS specific portions of the runtime library need not be. a discussion about the usefulness of such warning is warranted. This includes. ISO C does not specify something. Following these suggestions is quite likely to save programmers much time and frustration. ISO C library stream functions are sufficient and perform very well. For instance. structure alignment. [edit] Compiler Warnings Nearly all of the Open Watcom subprojects are set up to build with maximum warnings and treat warnings as errors. either POSIX or Win32 file I/O (in that order) should be used. If. say. do not rely on any particular implementation. it can be used. many other items. but is not limited to. type sizes. enumeration sizes. on the Win32 platforms. Nearly always there is a way to write code so that no warnings are reported. but eg. In general.simply because there is no danger of porting that code to any other compiler or platform. char signedness. That is a defence against programmers trying to write sloppy code. . Only if a feature not provided by the ISO C library is required. the Win386 extender) no other compiler comes close in capabilities and Open Watcom specific extensions may be used freely -.Recommended Practice and Pitfalls This section details recommended programming practice as well as some common pitfalls and gotchas.

select a suitable type sufficient to hold the range of expected values. Only use explicit casts where the default conversions don't do the job. Use it especially for functions that take pointer arguments but do not modify the storage that the argument points to. [edit] Types and Conversions Programmers need to have a good understanding of the C type system. and more importantly it helps programmers. may not do what you expect and explicit L suffix is necessary. always use types with explicitly specified width. usually int or long. Keep in mind that a constant such as 123 will have type int. This is often the case with many text processing functions that take strings as arguments but do not modify them. Also do not assume that pointers have specific width. [edit] Use of 'const' Use the const modifier where applicable. casts should not be used indiscriminately as they tend to obscure the purpose of code. or hardware. such as size_t. For writing portable code. he or she will know that the string won't be modified so it's not necessary to create a copy and it could be stored read-only memory. However. In general. Keep in mind that default promotions will be applied to the variadic arguments. networking protocols. Never ever assume that int or long has specific width. in other cases. pid_t. Same goes for arithmetic involving variables . The C99 types such as uint32_t. If a programmer sees that a function takes a pointer to const char. there are two simple rules:   use specific width types if required use generic types in all other cases That is. int16_t. etc. etc. are recommended. Use the C99 uintptr_t or intptr_t types if you need to convert between integers and pointers. The const modifier may help the compiler take advantage of additional optimization opportunities. if specific types are imposed by file formats. That is the only way to ensure that the type system will work for you. . do use types designed for specific applications. Constructs such as long l = 1024 * 1024. On the other hand.explicit casts may be required to achieve desired results. not against you. Be extremely careful with functions that take variable number of arguments. which has different size on different platforms. off_t.[edit] Type Selection There is an art to selecting basic types in C and C++.

x ) . In ideal case. Problems caused by improper structure packing are notoriously difficult to diagnose. keep in mind the following recommendations. If necessary.. [edit] Enumeration Sizes Do not assume that enumeration variables have specific size. #pragma pack( pop ) form is recommended.[edit] Use of 'static' Use the static storage class liberally. Keeping functions and variables static also helps prevent name space pollution. proper alignment is critical. However. For structures that are only used internally within a single project. Only use plain char objects to hold text. They might be int sized or they might not be. it is highly recommended to use compiler default packing. or use casts. Do not peform arithmetic on such objects (except perhaps subtraction). without worrying about other modules. [edit] . [edit] Structure Packing Structure packing can be a source of interesting problems. many structures aren't naturally aligned (especially those designed on nonRISC architectures or by incompetent programmers) and proper packing must be specified.. There is unfortunately no standardized way to specify structure packing. as there is no danger that objects with static storage might conflict with objects defined in other modules. However. The compiler may take advantage of additional optimization opportunities. a static function that is always inlined need not be emitted in its non-inline form. the #pragma pack( push. If you need to store enumeration values in a structure with externally imposed layout. In reality. It is important for both the compiler and the programmer. for instance. declare such objects with explicit sign. received over network links etc. To avoid most of them. structures are designed to be naturally aligned and structure packing becomes irrelevant. use a type with explicitly specifed width for storage. as it is supported by many compilers. the maintainer must only examine the module where the object is defined. This is especially important on platforms where misaligned accesses incur significant penalties (that includes nearly all modern processor architectures) or raise processor exceptions. and do not use them for indexing into arrays.. for structures that describe external data stored in files. because when modifying a static variable or function. Static objects also greatly ease maintenance. [edit] Char Signedness Do not assume that plain char is either signed or unsigned.

keep in mind that the path separator may be a forward slash. as their layout will be quietly altered when endianness changes. provide two variants of the code. Explicitly open binary files as binary and text files as text. On the other hand. [edit] File Creation and Opening Make sure that files are opened with proper mode. When creating files. with no spaces or other funny characters. . preferably all lowercase. a backslash. Be especially careful with unions and bitfields. When a sequence of bytes is stored in memory (a text string. many other platforms do. make sure appropriate access rights are used. for instance). when using POSIX style I/O. While Win32 may not have user/group/other access flags. [edit] Filesystem Naming Conventions Don't get inventive with file names. When writing code that needs to parse pathnames. If the ordering is significant.Endianness Issues Write code that does not depend on ordering of bytes within words when they are stored in memory. or (on Win32 or OS/2) either. While UNIX may not distinguish between text and binary files. Use the __BIG_ENDIAN__ macro to test for big endian targets. keep in mind that reading the storage as words or doublewords is going to have different results on the 'other' platform. many other platforms do. Stick to alphanumeric characters. Use the __UNIX__ macro to test if UNIX naming conventions should be followed. do not assume that the system does not care about access flags.

Mitze E.A. The scope is coding style. Milner R. University of Washington Mark Brader SoftQuad Incorporated Toronto Abstract This document is an updated version of the Indian Hill C Style and Coding Standards paper.W. Schan N. not functional organization. with modifications by the last three authors.Recommended C Style and Coding Standards L. It describes a recommended coding standard for C programs. Kirchhoff J. Elliott L. Whittington Bell Labs Henry Spencer Zoology Computer Systems University of Toronto David Keppel EECS. Cannon R. .H.W.O.P. UC Berkeley CS&E.W.M. Miller J.

The editor may not have enough temp space . the goal of these standards is to increase portability. not to be clear is unprofessional. Programmers who encounter unusual situations should consult either experienced C programmers or code written by experienced C programmers (preferably following these rules).8] on C style into a uniform set of standards that should be appropriate for any project using C. Good style should encourage consistent layout. spacing. Of necessity. The scope of this work is C coding style.'' -. improve portability. Although there is no maximum length limit for source files. these standards cannot cover all situations. We (see footnote 1) have tried to combine previous work [1. Many of the style choices here are somewhat arbitrary. but individual institutions or groups may adopt part or all of them as a part of program acceptance. naming conventions) of the existing code than it is to blindly follow this document. commenting. The standards in this document are not of themselves required.6. File Organization A file consists of various sections that should be separated by several blank lines. Experience and informed judgement count for much. 2.1. and above all improve clarity. Ultimately. The scope of this work is C coding style. Introduction This document is a modified version of a document from a committee formed at AT&T's Indian Hill labs to establish a common set of coding standards and recommendations for the Indian Hill community. and reduce errors. files with more than about 1000 lines are cumbersome to deal with. Mixed coding style is harder to maintain than bad coding style. This work does not cover functional organization.Sir Ernest Gowers. although parts are biased towards particular systems. or general issues such as the use of gotos. When changing existing code it is better to conform to the style (indentation. reduce maintenance. ``To be clear is professional. It is therefore likely that others at your institution will code in a similar style.

Since much C code is also C++ code. .sav''). including .g.o Include header file names end in . These rules apply to both program files and default files used and produced by the program (e. 2.s.c. The first character of the name should be a letter and all characters (except the period) should be lower-case letters and numbers.c. there is no clear solution here. Some compilers and tools require certain suffix conventions for names of files [5].c.C. Many rows of asterisks. present little information compared to the time it takes to scroll past..c Assembler source file names must end in .h. .to edit the file.cc. compilations will go more slowly. ``foo.g. In addition.c. ``rogue. Excessively long lines which result from deep indenting are often a symptom of poorly-organized code. The following conventions are universally followed:     Relocatable object file names end in . Lines longer than 79 columns are not handled well by all terminals and should be avoided if possible. The following suffixes are required:   C source file names must end in . The base name should be eight or fewer characters and the suffix should be three or fewer characters (four.2 Program Files The suggested order of sections for a program file is as follows: .h (e. . and .ch''). and an optional period and suffix. Yacc source file names end in . 2. if you include the period). it is conventional to use ``Makefile'' (not ``makefile'') for the control file for make (for systems that support it) and ``README'' for a summary of the contents of the directory or directory tree. for example.. An alternate convention that may be preferable in multi-language environments is to suffix both the language type and .l C++ has compiler-dependent suffix conventions.c.h'' or ``foo.1 File Naming Conventions File names are made up of a base name. and are discouraged. etc.y Lex source file names end in .

The statement #include "math. If a set of defines applies to a particular piece of global data (such as a flags word). and should be in some sort of meaningful order. 3. are defined at the system level and must included by any program using the standard I/O library. Any defines and typedefs that apply to the file as a whole are next. Also. Header files are also used to contain data declarations and defines that are needed by more than one program. references. Some. 2.h should be included before user include files. usually in the order: externs. 4. then ``function'' macros. 5. Header files should be functionally organized. Like functions should appear together.h. if a set of declarations is likely to change when code is ported from one machine to another. such as stdio. consider alphabetical order. static globals. the defines should be immediately after the data declaration or embedded in structure declarations. First in the file is a prologue that tells what is in that file. The prologue may optionally contain author(s). If the include is for a non-obvious reason. system include files like stdio. A description of the purpose of the objects in the files (whether they be functions. Avoid private header filenames that are the same as library header filenames. Any header file includes should be next. etc. In most cases. Next come the global (external) data declarations.e. external data declarations or definitions. or something else) is more useful than a list of the object names. If defining large numbers of essentiallyindependent utility functions. non-static globals.h" . The functions come last. One normal order is to have ``constant'' macros first. Considerable judgement is called for here. then typedefs and enums. the reason should be commented. 2.3 Header Files Header files are files that are included in other files prior to compilation by the C preprocessor. those declarations should be in a separate header file. revision control information. i. declarations for separate subsystems should be in separate header files. indented to put the defines one level deeper than the first keyword of the declaration to which they apply. A ``breadth-first'' approach (functions on a similar level of abstraction together) is preferred over depth-first (functions defined as soon as possible before or after their calls)..1.

Header files should not be nested. Use the<name> construction for getting them from a standard place. That way. #ifndef EXAMPLE_H #define EXAMPLE_H . comment this fact. If this is what you want to happen. Frequently it is a symptom of poor partitioning of code between files. the compiler can do type checking and the external declaration will always agree with the definition. The ``include-path'' option of the C compiler (-I on many systems) is the best way to handle extensive private libraries of header files. On some systems.will include the standard library math header file if the intended one is not found in the current directory. . it is common to include a list of all conditional compilation flags and what they mean.. describe what other headers need to be #included for the header to be functional. Also.h file to prevent accidental doubleinclusion. /* body of example. therefore. For example. where a large number of header files are to be included in several different source files. The prologue for a header file should. Header files that declare functions or external variables should be included in the file that defines the function or variable. repeating uninitialized declarations without the extern keyword also causes problems. In extreme cases. particularly to perform nested includes. Defining variables in a header file is often a poor idea. it is acceptable to put all common #includes in one include file.4 Other Files It is conventional to have a file called ``README'' to document both ``the bigger picture'' and issues for the program as a whole. etc. Don't use absolute pathnames for header files. 2.. some objects like typedefs and initialized data definitions cannot be seen twice by the compiler in one compilation. It is common to put the following into each . It is also common to list files that are machine dependent. Repeated declarations can happen if include files are nested and will cause the compilation to fail. it permits reorganizing the directory structure without having to alter source files. or define them relative to the current directory.h file */ #endif /* EXAMPLE_H */ This double-inclusion mechanism should not be relied upon.

and the closing */ in columns 2-3. etc. * The comment text should be tabbed or spaced over uniformly. Just making code faster is not enough to rationalize a hack.Comments ``When the code and the comments disagree. no leading * before lines of text. Very long block comments such as drawn-out discussions and copyright notices often start with /* in columns 12. Comments that describe data structures. the performance must be shown to be unacceptable without the hack.'' -. as such information rapidly gets out of date. how it is being done. a * in column 2 before each line of comment text. The justification should be that something bad will happen if unoffensive code is used. and put the closing */ also in 1-2. An alternative is to have ** in columns 1-2. and they should be tabbed over to the same tab . C is not assembler. however. and the closing*/ in columns 1-2. should be in block comment form with the opening /* in columns 1-2. Comments that disagree with the code are of negative value. which globals are used and which are modified. Comments should justify offensive code. Block comments inside a function are appropriate. Short comments should be what comments. The comment should explain the unacceptable behavior and describe why the hack is a ``good'' fix..Norm Schryer The comments should describe what is happening. what parameters mean. algorithms. comments that are clear from the code. and any restrictions or bugs. * The opening slash-star and closing star-slash are alone on a line. */ /* ** Alternate format for block comments */ Note that grep '^. both are probably wrong.\e*' will catch all block comments in the file (see footnote 2). rather than how comments such as ``sum of values divided by n''. Avoid. such as ``compute mean value''. /* * Here is a block comment. putting a comment at the top of a 3--10 line section telling what it does overall is often more useful than a comment on each line describing micrologic.

*. Unrelated declarations. should be on separate lines. char *s. each element should be alone on a line with a comment describing it. } else { b = isprime(a). One-line comments alone on a line should be indented to the tab setting of the code that follows. } /* special case */ /* works only for odd a */ Declarations Global declarations should begin in column 1.setting as the code that they describe. which is wrong. *u. Use the tab character rather than blanks (spaces). } } Very short comments may appear on the same line as the code they describe. since t and u do not get declared as pointers. If more than one short comment appears in a block of code they should all be tabbed to the same tab setting. All external data declaration should be preceded by the extern keyword. Repeated size declarations are particularly beneficial to someone picking up code written by another.g. even of the same type. t. and should be tabbed over to separate them from the statements. if (argc > 1) { /* Get input file from command line. if (a == EXCEPTION) { b = TRUE. with the exception that a list of #defined constants do not need comments if the constant names are sufficient documentation. The opening brace ( {) should . then the array bounds must be repeated in the extern declaration unless the size is always encoded in the array (e. and comments are usually tabbed so that they line up underneath each other. values. The ``pointer'' qualifier.. should be with the variable name rather than with the type. stdin) == NULL) { perror (argv[1]). If an external variable is an array that is defined with an explicit size. instead of char* s. For structure and union template declarations. The names. A comment describing the role of the object being declared should be included. */ if (freopen(argv[1]. "r". *t. a read-only character array that is always null-terminated). u.

YAWL. MOTOR }.type */ (1) (2) (3) (4) (5) /* water line length in meters */ /* see below */ /* sail area in square mm */ These defines are sometimes put right after the declaration of type. the number twenty-one. boat. /* sail area in square mm */ }. int x = 1.'' should never be used. or at the very least should be commented to indicate that C's default initialization to zero is being relied upon. struct boat { int int long }. YAWL. }. Variables in particular should be accessible from other files only when there is a clear need that cannot be filled in another way. Structure initializations should be fully parenthesized with braces. When the actual values are unimportant. { 28. for example two long 2l looks a lot like 21. /* defines for #define KETCH #define YAWL #define SLOOP #define SQRIG #define MOTOR wllength. and the closing brace (}) should be in column 1. with enough tabs after the # to indent define one level more than the structure member declarations. The empty initializer. /* water line length in meters */ enum bt type. sailarea. In any file which is part of a larger whole rather than a self-contained program. 6000000L }. MOTOR. Constants used to initialize longs should be explicitly long. the enum facility is better (see footnote 3).be on the same line as the structure tag. SLOOP. maximum use should be made of the static keyword to make functions and variables local to single files. within the struct declaration. { 0 }. type. Such usage should be commented to make it clear that another file's variables are being used. /* what kind of boat */ long sailarea. enum bt { KETCH=1. ``{ }. char *msg = "message". Use capital letters. struct boat { int wllength. struct boat winner[] = { { 40. SQRIG. the comment . 0L }. Any variable whose initial value is important should be explicitly initialized.

One common mistake is to omit the declaration of external math functions that return double. use them. typedef struct splodge_t { int sp_count. The opening brace of the function body should be alone on a line beginning in column 1. if each declaration is on its own line. declare them as STATIC and #define STATIC as needed. If function prototypes are available. otherwise it can be on the same line as the return type. string pointers called ``s''. even if they are only integers. Structures may be typedeffed when they are declared. (optionally) indented one stop (see footnote 4). The function name (and the formal parameter list) should be alone on a line. Discussion of non-trivial design decisions and side-effects is also appropriate. in a comment on that line. Do not default to int. } splodge_t. The compiler then assumes that the return value is an integer and the bits are dutifully converted into a (meaningless) floating point value. If the value returned requires a long explanation. char *sp_name. as the unique name makes the program easier to read (as long as there are only a few things typedeffed to integers!).should name the other file.Michael DeCorte Function Declarations Each function should be preceded by a block comment prologue that gives a short description of what the function does and (if not clear) how to use it. Give the struct and the typedef the same name. ``C takes the point of view that the programmer is always right. All formal parameter declarations.'' -. Loop counters called ``i''. This may either be done in the function comment or. Destination (return value) parameters should generally be first (on the left). Each parameter should be declared (do not default to int). The most important types should be highlighted by typedeffing them. and integral types called ``c'' and used . Avoid duplicating information clear from the code. in column 1. The function return type should be alone on a line. In general the role of each variable in the function should be described. If your debugger hides static objects you need to see during debugging. *sp_alias. The return type of functions should always be declared. tabbed over. local declarations and code within the function body should be tabbed over one stop. if the function does not return a value then it should be given return type void (see footnote 5). it should be given in the prologue.

i.}"]. Better to design an interface that uses a fixed number of arguments.}read(j. If a group of functions all have a like parameter or local variable. world!\\n". the potential confusion is enough that lint will complain about it when given the --h option.. avoid using the same name for different purposes in related functions. Comments for parameters and local variables should be tabbed so that they line up underneath each other. 1984.Dishonorable mention. there should be at least 2 blank lines between the end of one function and the comments for the next. If the function uses any external variables (or functions) that are not declared globally in the file. Be careful when you use or declare functions that take a variable number of arguments (``varargs''). Whitespace int i.read('-'-'-'. There is no truly portable way to do varargs in C.main(){for(.i---j. A long string of conditional operators should be split onto separate lines.for characters are typically excluded. it helps to call the repeated variable by the same name in all functions. Author requested anonymity. local variables should not be redeclared in nested blocks.i+++"hell\ o.} -.++i){--i.i["]<i. e.p){write(j/p+p. use the library macros for declaring functions with variant argument lists.g. Indentation and spacing should reflect the block structure of the code. Local variable declarations should be separated from the function's statements by a blank line.) Like parameters should also appear in the same place in the various argument lists. Avoid local declarations that override declarations at higher levels.. these should have their own declarations in the function body using the extern keyword. if (foo->next==NULL && totalcount<needed && needed<=MAX_ALLOT && server_active(current_input)) { . Obfuscated C Code Contest. Use vertical and horizontal whitespace generously. In particular. Although this is valid C.i/i). If you must have varargs. .'/'/'/')).. (Conversely.

. Examples /* * * * * * */ Determine if the sky is blue by checking that it isn't night. (The sizeof operator is an exception.Might be better as if (foo->next == NULL && totalcount < needed && needed <= MAX_ALLOT && server_active(current_input)) { . May return TRUE when the answer is FALSE. CAVEAT: Only sometimes right. Other complex expressions. On the other hand. too.d. Return NULL if there is no last element. otherwise the C preprocessor will not recognize the argument list. : operator. Similarly. curr = curr->next ) { . /* true or false */ hour.. macro definitions with arguments must not have a blank between the name and the left parenthesis. eclipses.) Blanks should also appear after commas in argument lists to help separate the arguments visually. c = (a == b) ? d + f(a) : f(b) .c'. short days. trail = listp. are Keywords that are followed by expressions in parentheses should be separated from the left parenthesis by a blank.. Consider clouds. trail = &(curr->next). particularly those using the ternary ? best split on to several lines. NOTE: Uses `hour' from `hightime.. /* current hour of the day */ int skyblue() { extern int } /* * * * return (hour >= MORNING && hour <= EVENING). Returns `int' for compatibility with the old version. curr != NULL. elaborate for loops should be split onto different lines.. Find the last element in the linked list pointed to by nodep and return a pointer to it. for (curr = *listp.

if (f() != FAIL) is better than if (f()) even though FAIL may have the value 0 which C considers to be false. register node_t *lp. if (!(bufsize % sizeof(int))) should be written instead as if ((bufsize % sizeof(int)) == 0) . np != NULL. boogle (zork). lp = np. /* VOID */ return (lp).g. The null body of a for or while loop should be alone on a line and commented so that it is clear that the null body is intentional and not missing code. break. { register node_t *np. An explicit test will help you out later when somebody decides that a failure return should be --1 instead of 0.e. case FOO: case BAR: case BAZ: oogle (zork). while (*dest++ = *src++) . /* VOID */ Do not default the test for non-zero.*/ node_t * tail(nodep) node_t *nodep. oogle (gork). e. break. for (np = lp = nodep. np = np->next) . } Simple Statements There should be only one statement per line unless the statements are very closely related. boogle (zork). /* pointer to head of list */ /* advances to NULL */ /* follows one behind np */ if (nodep == NULL) return (NULL). break. oogle (bork). i. Explicit comparison should be used even if the comparison value will never change. boogle (bork)..

Thus. rename to isvalid()).. (b)) == 0) The non-zero test is often defaulted for predicates and other functions or expressions which meet the following restrictions:   Evaluates to 0 for false. not checkvalid. 0 1 or typedef enum { NO=0. nothing else.). do not check a boolean value for equality with 1 (TRUE.g. A frequent trouble spot is using strcmp to test for string equality.to reflect the numeric (not boolean) nature of the test. YES. but only non-zero if true. It is even better (where possible) to rename the function/variable or rewrite the expression so that the meaning is obvious without a comparison to true or false (e. b) (strcmp((a). while ((c = getchar()) != EOF) { process the character } . The special names improve readability immensely.).. There is a time and a place for embedded assignment statements. The preferred approach is to define a macroSTREQ.. #define STREQ(a. where the result should never ever be defaulted. etc. etc. must be written if (func() != FALSE) { . It is common practice to declare a boolean type bool in a global include file. YES } bool.. typedef int #define FALSE #define TRUE bool. Call a predicate isvalid or valid. if (func() == TRUE) { . Most functions are guaranteed to return 0 if false. instead test for inequality with 0 (FALSE. In some constructs there is no better way to accomplish the results without making the code bulkier and less readable. NO. Is named so that the meaning of (say) a `true' return is absolutely obvious. Even with these declarations..

For example. do functions with side effects. as in any well-structured code.. } } . Parameters to non-prototyped functions sometimes need to be promoted explicitly.) { . Using embedded assignment statements to improve runtime performance is also possible. while the difference in ease of maintenance will increase as the human memory of what's going on in the latter piece of code begins to fade.) { while (. However.. In the long run the time difference between the two will decrease as the optimizer gains maturity. with a success/failure return code. a function expects a 32-bit long and gets handed a 16-bit int instead. for many purposes. Goto statements should be used sparingly.. error: clean up the mess When a goto is necessary the accompanying label should be alone on a line and tabbed one stop to the left of the code that follows.. the stack can get misaligned. for example.. if (disaster) goto error. d = a + r. integral. .The ++ and -. one should consider the tradeoff between increased speed and decreased maintainability that results when embedded assignments are used in artificial places. Continue should be used sparingly and near the top of the loop. and floating-point values. although the need to do such a thing may indicate that the inner constructs should be broken out into a separate function. should not be replaced by d = (a = b + c) + r. a = b + c. and while nesting. Break is less troublesome.. So. Problems occur with pointer. If.operators count as assignment statements. for. even though the latter may save one cycle. The main place where they can be usefully employed is to break out of several levels of switch. The goto should be commented (possibly in the block header) as to its utility and purpose. for (...

if (expr) { statement. if you have one. /*FALLTHROUGH*/ case XYZ: statement.'' and is preferred if you haven't already got a favorite. Be consistent with your local standard. the last break is unnecessary. (that is. The fall-through feature of the C switch statement. when there is no break between a code segment and the next case statement) must be commented for future maintenance. When a block of code has several labels (unless there are a lot of them). With most other styles. the labels are placed on separate lines. if used. . The default case. the else part of an if-else statement and the while part of a do-while statement should appear on the same line as the close brace. case UVW: statement.Compound Statements A compound statement is a list of statements enclosed by braces. break. the statements of both the if and else sections should both be enclosed in braces (called fully bracketed syntax). When editing someone else's code. but is required because it prevents a fall-through error if another case is added later after the last one. break. } The style above is called ``K&R style. } Here. or pick one and use it consistently. A lint-style comment/directive is best. control { statement. With K&R style. Whenever an if-else statement has a compound statement for either the if or else section. should be last and does not require a break if it is last. always use the style used in that code. statement. switch (expr) { case ABC: case DEF: statement. the braces are always alone on a line. There are many common ways of formatting the braces.

Do-while loops should always have braces around the body. } Braces are also essential in if-if-else sequences with no second else such as the following.. { close_circ(circno). "no")) { . "maybe")) { . } } else { funcb().. "yes")) { statements for yes . if (expr) statement. } . } else if (STREQ (reply... } An if-else with else if should be written with the else conditions left-justified.. } else if (STREQ (reply.} else { statement. if (STREQ (reply.. statement.... else CLOSE_CIRCUIT(x) ++i.. } else { statements for default . } The format then looks like a generalized switch statement and the tabbing reflects the switch between exactly one of several alternatives rather than a nesting of statements. The following code is very dangerous: #ifdef CIRCUIT # define CLOSE_CIRCUIT(circno) #else # define CLOSE_CIRCUIT(circno) #endif . which will be parsed incorrectly if the brace after (ex1) and its mate are omitted: if (ex1) { if (ex2) { funca().

as in for statements. for instance those with nested ternary ? : operators. The comma operator is most useful to provide multiple initializations or operations. however. Operators Unary operators should not be separated from their single operand. expressions involving mixed operators should be parenthesized. continue . Sometimes an if causes an unconditional control transfer via break.Note that on systems where CIRCUIT is not defined the statement ++i. Too many parentheses. The else should be implicit and the code should not be indented. which may be clearer if the ``inner'' operators are not surrounded by spaces and the ``outer'' ones are. or return. The ``flattened'' indentation tells the reader that the boolean test is invariant over the rest of the enclosing block. consider breaking it across lines. if (level > limit) return (OVERFLOW) normal(). can make a line harder to read because humans aren't good at parenthesis-matching. The logical expression operand before the ? : should be parenthesized and both return values must be the same type.goto. but generally it should be avoided. Splitting at the lowest-precedence operator near the break is best.' and `->' should be separated from their operands by blanks. Naming Conventions . all binary operators except `. Some judgement is called for in the case of complex expressions. If you think an expression will be hard to read. return (level). will only get executed when expr is false! This example points out both the value of naming macros with CAPS and of making code fully-bracketed. can be confusing and should be avoided if possible. There are some macros like getchar where both the ternary operator and comma operators are useful. Complex expressions. Generally. There is a time and place for the binary comma operator. Since C has some unexpected precedence rules.

Defining the value in one place also makes it easier to . global names (including enums) should have a common prefix identifying the module that they belong with. Enum constants are Capitalized or in all CAPS Function. Some macros (such as getchar and putchar ) are in lower case since they may also exist as functions. Lower-case macro names are only acceptable if the macros behave like a function call. Most systems use them for names that the user should not have to know. and enum tag names should be in lower case. Some systems will include more library code than you want. There are some general rules however.        Names with leading and trailing underscores are reserved for system purposes and should not be used for any user-created names. If you must have your own private identifiers. Avoid names that might conflict with various standard library names. Sometimes it is impossible to write a macro that behaves like a function even though the arguments are evaluated exactly once. `l'.Individual projects will no doubt have their own naming conventions. Globals may alternatively be grouped in a global structure. Similarly. your program may be extended someday. Typedeffed names often have _t appended to their name. The potential for confusion is considerable. Many macro ``functions'' are in all CAPS. avoid foobar and foo_bar. like foo and Foo. Similarly. they evaluate their parameters exactly once and do not assign values to named parameters. begin them with a letter or two identifying the package to which they belong. The #define feature of the C preprocessor should be used to give constants meaningful names. `1' and `I' look quite similar. typedef. and variable names. Constants Numerical constants should not be coded directly. Avoid names that differ only in case. Symbolic constants make the code easier to read. Also. In general. A variable named `l' is particularly bad because it looks so much like the constant `1'. avoid names that look like each other. union. #define constants should be in all CAPS. that is. as well as struct. On many terminals and printers.

'\007').0 for a float instead of 540 with an implicit float cast. Non-text characters are discouraged as non-portable.. Macros Complex expressions can be used as macro parameters. When a value is a pointer it should be compared to NULL instead of 0. The macro should be used in implementing the function so that changes to the macro will be automatically .g. There is little that can be done about the problems caused by side effects in parameters except to avoid side effects in expressions (a good idea anyway) and.. since additional type checking is often available. they should be written using a escape character of three octal digits rather than one (e. if (front_door == 0) error("can't open %s\\\\n". At the very least. and operator-precedence problems can arise unless all occurrences of parameters have parentheses around them. The enumeration data type is a better way to declare variables that take on only a discrete set of values. NULL is available either as part of the standard I/O library's header file stdio. Even so. In the last example front_door is a pointer. For example if a for loop indexes through an array. There are times when it is impossible to write macros that act exactly like functions. use 540. 7).h for newer systems. If non-text characters are necessary. then for (i = 0. such usage should be considered machine-dependent and treated as such. door[i]). when possible.administer large programs since the constant value can be changed uniformly by changing only the define. Even simple values like 1 or 0 are often better expressed using defines like TRUE and FALSE (sometimes YES and NO read better). particularly if they are used in strings. i < ARYBOUND.h or in stdlib. any directly-coded numerical constant must have a comment explaining the derivation of the value.g. getc and fgetc). is not. Some macros also exist as functions (e. There are some cases where the constants 0 and 1 may appear as themselves instead of as defines.g. e. to write macros that evaluate their parameters exactly once. i++) is reasonable while the code door_t *front_door = opens(door[i]. Constants should be defined consistently with their use. Simple character constants should be defined as character literals rather than numbers.

If the semicolon is omitted after the call to SP3. }} while (0) Writing out the enclosing do-while by hand is awkward and some compilers and tools may complain that there is a constant in the while conditional. bv += x. while macro parameters are passed by name substitution. } ) Using STMT will help prevent small typos from silently changing programs. av = f (&x). Macros that take no parameters but reference variables. if (x==3) SP3(). then the else will (silently!) become associated with the if in the SP3 macro. e. bv += x. . the effect of the call/return becomes negligible. bv += x. or are aliases for function calls should be given an empty parameter list. #ifdef lint static int ZERO. since the global name may be hidden by a local declaration. Care is needed when interchanging macros and functions since function parameters are passed by value. av = f (&x).reflected in the function. A macro for declaring statements may make programming easier. With the semicolon. so a function should be used instead. In some cases it is appropriate to make the compiler insure that a macro is terminated with a semicolon. Macros that change named parameters (rather than the storage they point at) or may be used as the left-hand side of an assignment should mention this in their comments. the else doesn't match any if ! The macro SP3 can be written safely as #define SP3() \\\\ do { if (b) { int x. Carefree use of macros requires that they be declared carefully. else BORK(). Macros should avoid using globals. #else # define ZERO 0 #endif #define STMT( stuff ) do { stuff } while (ZERO) Declare SP3 with #define SP3() \\\\ STMT( if (b) { int x. av = f (&x). but when a macro gets long. #define OFF_A() (a_global+OFFSET) #define BORK() (zork()) #define SP3() if (b) { int x. are long.. } Macros save function call/return overhead.g.

Put #ifdefs in header files instead of source files when possible. For instance. Instead. Thus. #ifdef BSD4 long t = time ((long *)NULL). . and there may be non-4BSD systems for which the above is the best code. If you #ifdef machine dependencies.h. debugging. Use the #ifdefs to define macros that can be used uniformly in the code. and for setting certain options at compile-time.. MALLOC(size) (malloc(size)) Conditional compilation should generally be on a feature-by-feature basis. Conditional Compilation Conditional compilation is useful for things like machine-dependencies. even if the #ifdef is false. even if the #ifdeffed part of the file never gets compiled (e. (Use #error and indent it so it works with older compilers. the result is an error.) If you #ifdef optimizations. #ifdef COMMENT). Various controls can easily combine in unforeseen ways. MALLOC(size) (mm_malloc(size)) void *malloc().Except for type casts. use define symbols such asTIME_LONG and TIME_STRUCT and define the appropriate one in a configuration file such as config. sizeof.g. Beware of conditional compilation. Machine or operating system dependencies should be avoided in most cases. a header file for checking memory allocation might look like (omitting definitions forREALLOC and FREE): #ifdef DEBUG extern # define #else extern # define #endif void *mm_malloc(). make sure that when no machine is specified. it cannot be arbitrary text. Note that the text inside of an #ifdeffed section may be scanned (processed) by the compiler. the default should be the unoptimized code rather than an uncompilable program. macros should contain keywords only if the entire macro is surrounded by braces. not a default machine. Be sure to test the unoptimized code. and hacks such as the above. #endif The preceding code is poor for two reasons: there may be 4BSD systems for which there is a better choice.

/* * INPUT: A null-terminated source string `src' to copy from and .. the first enum constant should have a non-zero value. VAL_DEAD } value_t. C code run. enum { VAL_NEW=1. VAL_DYING. When bound checks fail. or the first constant should indicate an error. even from functions that ``can't'' fail.. some `magic' value of maxsize should mean ``no bounds checks''. then MALLOC will select the appropriate allocator. Check for error return values. make sure that the function does something useful such as abort or return an error status. For instance. STATE_START. and that intermediate results are well-formed. Include a lot of debugging and error-checking code and leave most of it in the finished product. #ifdef DEBUG # define MALLOC(size) #else # define MALLOC(size) #endif (mm_malloc(size)) (malloc(size)) Check bounds even on things that ``can't'' overflow. code. STATE_END } state_t. enum { STATE_ERR. VAL_NORMAL. STATE_NORMAL. PLEASE!!!'' -. Write your own functions so that they test for errors and return error values or abort the program in a well-defined way. If there are times when the size of the destination is unknown. avoids littering the code with #ifdefs.Barbara Tongue If you use enums. run. Consider that close() and fclose() can and do fail. even when all prior file operations have succeeded. Run. and makes clear the difference between allocation calls being debugged and extra memory that is allocated only during debugging. if mm_malloc is a debugging memory allocator. Check even for ``impossible'' errors. [8] Use the assert facility to insist that each function is being passed well-defined values. Build in the debug code using as few #ifdefs as possible.Debugging ``C Code. A function that writes on to variable-sized storage should take an argument maxsize that is the size of the destination. Uninitialized values will then often ``catch themselves''.

The header files will contain #defines and typedefs that may vary from machine to machine. a different compiler. worry about detail optimizations only on machines where they prove necessary. */ char * copy (dest.> 0) if ((*dp++ = *src++) == '\\\\0') return (dest). Portability ``C combines the power of assembler with the portability of assembler. } In all. while (maxsize\-\. The same is true of programs that crash occasionally or clobber valid data. In general.* a `dest' string to copy to. src) char *dest. unsigned maxsize. * `dest' is modified even when the copy fails. The advantages of portable code are well known. alluding to Bill Thacker. Optimizations for one machine may produce worse code on another. a new ``machine'' is different hardware.Anonymous. and `src' must be no longer than * `dest'. * OUTPUT: The address of `dest' or NULL if the copy fails. `maxsize' is the size of `dest' * or UINT_MAX if the size is not known. Optimized code is often obscure. remember that a program that produces wrong answers twice as fast is infinitely slower. *src. Reference [1] contains useful information on both style and portability. Here. This section gives some guidelines for writing portable code. or any combination of these.'' -. maxsize. return (NULL). ``portable'' means that a source file can be compiled and executed on different machines with the only change being the inclusion of possibly different header files and the use of different compiler flags. `src' and `dest' must * both be shorter than UINT_MAX. Document . The following is a list of pitfalls to be avoided and recommendations to be considered when designing portable code:  Write portable code first. { char *dp = dest. a different operating system.

and code that is designed to support a particular piece of hardware. Assume that the compiler or hardware does it some completely screwy way. such as an assembler or I/O driver. Then if the program is to be moved to a new machine. Even in these cases there are many routines and data organizations that can be made machine independent. The size you get can depend both on the compiler and on various compile-time flags. type pdp11 VAX/11 68000 Cray-2 Unisys Harris 80386 series char 8 8 16 32 32 32 32 32 family 8 8 1100 H800 9 8 24 24 48 24 24 24 8 8/16 16/32 32 16/32/48 16/32/48 16/32/48 short 16 int long 16 32 8/16 64(32) 18 16/32 64(32) 36 32 32 32 32 64 64 36 72 char* 16 int* 16 64(24) 72 64 576 int(*)() 16  Some machines have more than one possible size for a given type. Pointers are not always the same size as ints. The following table shows bit sizes for basic types in C for various machines and compilers.g. Documentation should explain how it works and why it was needed (e. or freely interconvertible. the same size as each other. Pay attention to word sizes.. . Comment the machine dependence in the headers of the appropriate files. Any behavior that is described as ``implementation defined'' should be treated as a machine (compiler) dependency. Objects may be non-intuitive sizes. ``loop executes 6 zillion times''). it is a much easier task to determine what needs to be changed. Organize source files so that the machine-independent code and the machinedependent code are in separate files. Examples are code to deal with particular hardware registers such as the program status word. Recognize that some things are inherently non-portable.    performance hacks and localize them as much as possible.

The void(*)() type is guaranteed to be able to hold a pointer to any function. but a long cast into an int and back to a long may be truncated to 32 bits. free (p). say. For example. and is different from any other . The resulting pointer is called a null pointer for that type.The following table shows ``safe'' type sizes on the majority of systems. in older compilers).     Note that the size of an object does not guarantee the precision of that object. The integer constant zero may be cast to any pointer type. Even when. int *p = (int *) malloc (sizeof(int)). (Use char* and char(*)(). they may have different formats. Use these types when you need a generic pointer. Be sure to cast pointers back to the correct type before using them. an int* and a char* are the same size. Unsigned numbers are the same bit size as signed numbers. Type Minimum No Smaller # Bits char 8 char short int Than short 16 int long float 16 32 24 double 38 any * 14 char * 15 void * 15 float any * any *   The void* type is guaranteed to have enough bits of precision to hold a pointer to any data object. the following will fail on some machines that have sizeof(int*) equal to sizeof(char*). respectively. The code fails because free expects a char* and gets passed an int* . The Cray-2 may use 64 bits to store an int.

When non-zero integer constants are cast to pointer types. Thus. Null pointers are not always stored with all bits zero. Null pointers for two different types are sometimes different. pointers that access the same storage may compare as different. they will compare as equal. On some machines. A null pointer always compares equal to the constant zero.c */ #define X_FAIL (NULL) #define X_BUSY (&x_int_dummy) #define X_FAIL (NULL) #define X_BUSY MD_PTR1 /* MD_PTR1 from "machdep. On some VAXes. /* in x. For example. may or may not compare equal. Remember that characters may hold (much) more than 8 bits. and they may or may not access the same storage (see footnote 6).9 times 5. 4. Code that assumes signed/unsigned is unportable. These are independent of the size of the object. they may become identical to other pointers. If you must assume. Do not depend on this. On ANSI compilers. Watch out for signed characters. . A null pointer might not compare equal with a variable that has the value zero. which is not the case on many other machines. Avoid assuming ASCII. either allocate some storage or treat the pointer as a machine dependence. comment them as SIGNED or UNSIGNED . The following two pointers. a double may have less range or precision than a float.1 will yield two different numbers on two different machines. Also. On nonANSI compilers. when two pointers of the same type access the same storage. for instance. characters are sign extended when used in expressions. ((int *) 2 ) ((int *) 3 )   If you need `magic' pointers other than NULL. Differences in rounding and truncation can give surprisingly different answers. overflow (underflow) for a 32-bit floating-point number will happen at different values on different machines. document and localize. If you must assume signed or unsigned characters. A null pointer of one type cast in to a pointer of another type will be cast in to the null pointer for that second type. pointer of that type. array[c] won't work if c is supposed to be positive and is instead signed and negative. Unsigned behavior can be guaranteed with unsigned char. On some machines the first half of a double may be a float with similar value. for instance. extern int x_int_dummy.h" */      Floating-point numbers have both a precision and a range.

pointers to objects may not be interchanged freely. machine-dependent code should be #ifdeffed or operations should be performed by #ifdeffed macros. then useint.    Code that takes advantage of the two's complement representation of numbers on most machines should not be used. it is nonportable to concatenate any two variables. The bytes of a word are of increasing significance with increasing address on machines such as the VAX (little-endian) and of decreasing significance with increasing address on other machines such as the 68000 (big-endian). saving an integer through a pointer to 4 bytes starting at an odd address will sometimes work. even when given elements are the same size on all machines. If absolutely necessary. typedef ``sized'' types. Alignment considerations and loader peculiarities make it very rash to assume that two consecutively-declared variables are together in memory. a double word) might not be the same. You should weigh the time savings with the potential for obscure and difficult bugs when your code is moved. Hence any code that depends on the left-right orientation of bits in an object deserves special scrutiny. In general. start only at an even address. a structure of a 32-bit pointer and an 8-bit character may be 3 sizes on 3 different machines. Optimizations that replace arithmetic operations with equivalent shifting operations are particularly suspect. Pointer-to-character is a particular trouble spot on machines which do not address to the byte. sometimes cause a core dump. For instance. if the word size or value range is important. or start only at a multiple-of-four address. Unsigned types other than unsigned int are highly compiler-dependent. [1. Thus.3] Actually. since it will get the most efficient (natural) unit for the current machine. . on various machines a 4-byte integer may start at any address. or that a variable of one type is aligned appropriately to be used as another type. If a simple loop counter is being used where either 16 or 32 bits will do. to make it easier to change them and to aid in finding width-sensitive code. a particular structure may have its elements at different offsets on different machines. The order of bytes in a word and of words in larger objects (say. Large programs should have a central header file which supplies typedefs for commonly-used width-sensitive types. Bit fields within structure members will only be portable so long as two separate fields are never concatenated and treated as a unit. As a corollary. and sometimes fail silently (clobbering other data in the process). Indeed. Data alignment is also important.

One compiler may use several (incompatible) calling conventions. so a char might be passed as an int. getchar()). sometimes the program will run but clobber data. char foo (c1. { char bar = *(&c1 + 1). size. is very nonportable. The address space may have holes. Specifically. right-to-left. a pointer into an array of objects may legally point to the . Suspect unions used for type cheating. Do not depend on this. c2. Arguments may be pushed left-to-right. Simply computing the address of an unallocated element in an array (before or after the actual storage of the array) may crash the program. or passed in registers (not pushed at all). c = foo (getchar(). Do not modify string constants (see footnote 7). }              /* often won't return c2 */ This example has lots of problems. strcpy (&s[8]. The following code. for instance. The order of evaluation may differ from the order in which they are pushed. Do not make assumptions about the parameter passing mechanism.   There may be unused holes in structures. there need not even be a stack!). give wrong answers. c3. In ANSI C. If the address is used in a comparison. c3) char c1. return (bar). a value should not be stored as one type and retrieved as another. for instance. or loop forever. Structure pointers are not a problem.      On some machines. The stack may grow up or down (indeed. especially pointer sizes and parameter evaluation order. in arbitrary order. c2. ttychars). Parameters may be widened when they are passed. etc. One particularly notorious (bad) example is s = "/dev/tty??". Different compilers use different conventions for returning structures. An explicit tag field for unions may be useful. This causes a problem when libraries return structure values to code compiled with a different compiler. the null character pointer ((char *)0) is treated the same way as a pointer to a null string.

i = old i = a[i] = new.   first element after the end of the array. Side effects within expressions can result in code whose semantics are compiler-dependent. bar = bar->next = tmp. . Notorious examples include the following. It is only portable to use <<. This ``outside'' pointer may not be dereferenced. Although this appears to violate the rule that ``assignment proceeds right-to-left''. bar can be assigned before bar->next. In the second example. >. since C's order of evaluation is explicitly undefined in most places. Bitfields do not have these problems. However. } bar. or >= to compare pointers when they both point in to (or to the first element after) the same array. it is a legal interpretation. i may be assigned the value ``(long)(short)new'' before a[i] is assigned to. bar->next = bar = tmp. a[i] = b[i++]. x &= 0177770. <=. Compilers do differ. struct bar_t { struct bar_t *next. Only the == and != comparisons are defined for all pointers of a given type. The index into a could be the value of i either before or after the increment. we know only that the subscript into b has not been incremented. It is likewise only portable to use arithmetic operators on pointers that both point into the same array or the first element afterwards.  In the above example. short a[N]. On other machines it will also clear the upper two bytes. the address of bar->next may be computed before the value is assigned to bar. Use instead x &= ~07 which works properly on all machines. The value that i is assigned must be a value that is typed as if assignment proceeded right-to-left. In the third example. The following code will clear only the three rightmost bits of an int on some 68000s. Consider the following example: long i. this is usually safe in older implementations. Word size also affects shifts and masks.

. #define LOOKUP(chr) #define LOOKUP(c) (a['c'+(chr)]) /* Works as intended. be aware of the differences between the common libraries (such as ANSI. it's a fruitful source of bugs. because another reader has to figure out whether you're doing something special in that reimplemented stuff to justify its existence. If your compiler has switches to turn on warnings. Tricks such as using /**/ for token pasting and macros that rely on argument string expansion will break reliably.(filename))) Be aware. #define FOO(string) .     Be suspicious of numeric values appearing in the code (``magic numbers''). (But not too familiar. It also prevents your program from taking advantage of any microcode assists or other means of improving performance of system routines. terminal control routines. use them. Use lint when it is available. (printf("string = %s"..(string))) Will only sometimes be expanded to (printf("filename = %s". Suspect labels inside blocks with the associated switch or goto outside the block. It is a valuable tool for finding machinedependent constructs as well as other inconsistencies or program bugs that pass the compiler. that tricky preprocessors may cause macros to break accidentally on some machines. */ The second version of LOOKUP can be expanded in two different ways and will cause code to break mysteriously. */ (a['c'+(c)]) /* Sometimes breaks. ``Rolling your own'' wastes your time and makes your code less readable.    Become familiar with existing library functions and defines. POSIX. Consider the following two versions of a macro.. as opposed to their external interfaces. Avoid preprocessor tricks. however. They are also often quite unportable. If possible. or making your own defines for system structures. The internal details of library facilities. are subject to change without warning. and so on). Furthermore. FOO(filename).) You should not be writing your own string compare routine.

ANSI C Modern C compilers support some or all of the ANSI proposed standard C.and compilerdependent) VOIDP type. The void* type is hard to get right simply. For example. The inter-procedural goto. It is easiest to create a new (machine. Programs may break quietly on these systems. Beware of compiler extensions. longjmp. Many implementations ``forget'' to restore values in registers. conditionally #define new (standard) keywords such as const and volatile in a global . Some linkers convert names to lower-case and some only recognize the first six letters as unique. Use explicit casts when doing arithmetic that mixes signed and unsigned values. the value can get promoted wrong. 17. there is no guarantee that it can do so reliably. and use features such as function prototypes.      Wherever the type is in doubt. constant storage. Whenever possible. since some older compilers understand void but not void*. parameters should be cast to the appropriate type. Even when it can. etc. document and consider them as machine dependencies. Do not use function calls as a place to do type cheating. A program cannot generally execute code in the data segment or write into the code segment. For instance. Standard C improves portability by insuring that all compilers accept the same input language and by providing mechanisms that try to hide machine dependencies or emit warnings about code that may be machine-dependent. usuallychar* on older compilers. #if __STDC__ .h file. and volatile storage. Standard C improves program performance by giving better information to optimizers. should be used with caution. write code to run under standard C. C has confusing promotion rules. If used. if a function expects a 32bit long and it is passed a 16-bit int the stack can get misaligned.1 Compatibility Write code that is easy to port to older compilers. so be careful. Declare critical values as volatile if you can or comment them as VOLATILE. Always cast NULL when it appears in non-prototyped function calls. Standard compilers pre-define the preprocessor symbol__STDC__ (see footnote 8).

the forward declaration must include the storage class. When a static function has a forward declaration.. the `#' for a preprocessor directive must be the first nonwhitespace character on a line. For ANSI compilers. the class must be ``static'' but global functions must still be declared as ``extern''.. not with ``#endif NAME''.2 Formatting .. define COMPILER_SELECTED A_TARGET define const define volatile define void int typedef char *voidp. Under older compilers it must be the first character on the line. define COMPILER_SELECTED # #endif #ifdef . ANSI trigraphs may cause programs with strings containing ?? to break mysteriously. The comment should not be used on short #ifdefs. . 17. the class must be ``extern''.. #endif #ifdef COMPILER_SELECTED # undef COMPILER_SELECTED #else { NO TARGET SELECTED! } #endif Note that under ANSI C. Thus.# #endif #ifdef # # # typedef void *voidp. An ``#ifdef NAME'' should end with either ``#endif'' or ``#endif /* NAME */''. as it is clear from the code. forward declarations of static functions should use a #define such as FWD_STATIC that is #ifdeffed as appropriate. For older compilers.

stall_t *stall) { . int const *s. void .. /* YES */ /* NO */ Prototyped functions merge parameter declaration and definition in to one list. possibly a byte. never NULL. Parameters should be commented in the function comment. int const *s. is incompatible with the definition void bork (c) char c. The non-prototyped (backwards-compatible) definition implies that c is always passed as an int (see footnote 9).The style for ANSI C is the same as for regular C. The problem can be avoided if parameters are promoted when the program is designed. Unfortunately. /* * `bp': boat trying to get in.. Because const and volatile have strange binding rules.. The above declaration works if the definition is prototyped. For example. The prototype says that c is to be passed as the most natural type for the machine. If a function has promotable parameters then the caller and callee must be compiled identically. *t. each const or volatile object should have a separate declaration. with two notable exceptions: storage qualifiers and parameter lists. * returns stall number. the prototyped declaration extern void bork (char c). * `stall': a list of stalls.. */ int enter_pier (boat_t const *bp. { . Either both must use function prototypes or neither can use prototypes. 17. 0 => no room. bork can be defined to take an int parameter.3 Prototypes Function prototypes should be used to make code more robust and to make it run faster.

4 Pragmas Pragmas are used to introduce machine-dependent code in a controlled way. 17. should terminate the program. For instance. Pragmas that change the system behavior (``required pragmas'') may not. short times)). #if __STDC__ # define PROTO(x) x #else # define PROTO(x) () #endif extern char **ncopies PROTO((char *s. It is easy to write external declarations that work with both prototyping and with older compilers (see footnote 10). Thus.. Pragmas are of two classes. Note that PROTO must be used with double parentheses.g. Pragmas must always be #ifdefed out for non-ANSI compilers. they must always be enclosed in machine-dependent #ifdefs. #if defined(__STDC__) && defined(USE_HAGGIS_PRAGMA) #pragma (HAGGIS) #endif ``The `#pragma' command is specified in the ANSI standard to have an arbitrary implementation-defined effect. it is generated using an automatic conversion tool. Required pragmas should be #ifdeffed so that compilation will abort if no pragma is selected.. When a non-prototyped version is needed. Be sure to indent the `#' character on the #pragma. Obviously. the syntax of ANSI pragmas makes it impossible to isolate them in machine-dependent headers. Unfortunately. Another might use it to indicate that a given statement. In the end. the prototyped syntax will cause non-ANSI compilers to reject the program.. when pragmas are used. `#pragma' first attempts .bork (char c) { . if reached. one compiler may use haggis to signal an optimization. Optimizations may safely be ignored. Unfortunately. pragmas should be treated as machine dependencies. it may be best to write in only one style (e. as older preprocessors will halt on it otherwise. with prototypes). Two compilers may use a given pragma in two very different ways. In the GNU C preprocessor.

It makes the program unintelligible to all but the perpetrator.        Don't change syntax via macro substitution. Common trouble spots include structure assignment and bitfields. Avoid assignment with implicit test. preprocessing does not continue. In any case. it tries to run GNU Emacs displaying the Tower of Hanoi. Use explicit tests. Always test floating-point numbers as <= or >=.'' -.Manual for the GNU C preprocessor for GNU CC 1. Don't use floating-point variables where discrete values are needed. if that fails. with the normal attention to detail of a careful programmer.) Sloppy programmers should learn to be careful programmers instead of relying on a beautifier to make their code readable. abool = bbool. You cannot generally predict which bugs a compiler has. Special Considerations This section contains some miscellaneous do's and don'ts. Using a float for a loop counter is a great way to shoot yourself in the foot. Programmers can do a better job of making clear the complete visual layout of a function or file. . syntactically correct programs and hence are not available when the need for attention to white space and indentation is greatest. Thus. Compilers have bugs. Accidental omission of the second = of the logical compare is a problem. it reports a fatal error.34. (In other words. and especially in the early design of handwritten algorithms or pseudo-code. and the compiler might get fixed in the meanwhile. The main person who benefits from good program style is the programmer him/herself. Do not rely on automatic beautifiers. if that fails. if (abool) { . You won't be able to write anything useful. You could write a program that avoids all constructs that are known broken on all compilers. if that fails. you might still encounter bugs.to run the game `rogue'.. some of the visual layout is dictated by intent rather than syntax and beautifiers cannot read minds.. you should write ``around'' compiler bugs only when you are forced to use a particular buggy compiler. it tries to run the game `hack'. never use an exact comparison (== or !=). Automatic beautifiers can only be applied to complete.

make the test explicit so that it doesn't get ``fixed'' later.. etc. The author never had a problem. but rather as a tool to use during and after changes or additions to the code.. The latter can be #defined to register on those machines with many registers.. Lint Lint is a C program checker [2][11] that examines C source files to detect and report type incompatibilities. potential program bugs. Lint can find obscure bugs and insure portability before problems occur. Modern compilers will put variables in registers automatically. mark the 2-4 most critical values as registerand mark the rest as REGISTER. fprintf ("Usage: foo -bar <file>\n"). but they will also pick up many botches. The use of lint on all programs is strongly recommended.. Note that `--p' (see footnote 11) checks function-call type-consistency for only a subset of library routines. But the program dumped core every time an ordinary user made a mistake on the command line. and it is expected that most projects will require programs to use lint as part of the official acceptance procedure. Many versions of lint will catch this. or other code that is likely to break during maintenance. Use the register sparingly to indicate the variables that you think are most critical. inconsistencies between function definitions and calls. /* VALUSED */ while (abool = bbool. Most options are worth learning.   Explicitly comment variables that are changed out of the normal control flow. In extreme cases. Some options may complain about legitimate things. It should be noted that the best way to use lint is not as a barrier that must be overcome before official acceptance of a program. while ((abool = bbool) != FALSE) { ..When embedded assignment is used.. abool) { . . One fun story is about is about a program that was missing an argument to fprintf. so programs should be linted both with and without --p for the best ``coverage''. Many messages from lint really do indicate something wrong. while (abool = bbool) { .

as well. make recompiles only those modules that have been changed since the last time make was used. These comments both shut up lint when the code otherwise makes it complain. libraries. (using the -t flag is suggested) rdist distribute sources to other hosts file.Lint also recognizes several special comments in the code. Note: doesn't remove Makefile. although it is a source file source undo what spotless did tags run ctags.c check out the named file from revision control .out' or 'debug' depend make transitive dependencies install install binaries. deinstall back out of ``install'' mkcat install the manual page(s) lint run lint print/list make a hard copy of all source files shar make a shar of all source files spotless make clean. use revision control to put away sources. and also document special code. During development. Some common conventions include: all always makes all binaries clean remove all intermediate files debug make a test binary 'a. It can be used to automate other tasks. etc. Make One other very useful tool is make [7].

In addition. and functions so that they may be understood easily. If a project establishes its own archive libraries. Project-Dependent Standards Individual projects may wish to establish additional standards beyond those given here. it should plan on supplying a lint library file [2] to the system administrators. . Localize optimizations since they are often confusing and may be ``pessimizations'' on other machines. systematic prefix conventions for functional grouping of global data and also for structure or union member names can be useful. Among the most important points are:   The proper use of white space and comments so that the structure of the program is evident from the layout of the code.      What additional naming conventions should be followed? In particular. To keep in mind that you or someone else will likely be asked to modify code or make it run on a different machine sometime in the future. Craft code so that it is portable to obscure machines. command-line defines can be given to define either Makefile values (such as ``CFLAGS'') or values in the program (such as ``DEBUG''). statements. The use of simple expressions. What kind of include file organization is appropriate for the project's particular data hierarchy? What procedures should be established for reviewing lint complaints? A tolerance level needs to be established in concert with the lint options to prevent unimportant complaints from hiding complaints about real bugs or inconsistencies. What kind of revision control needs to be used? Conclusion A set of standards has been presented for C programming style. The following issues are some of those that should be addressed by each project program administration group. The lint library file allows lint to check for compatible use of library functions.

it must be followed if it is to be useful. the widening rules require that all char and short parameters are passed as ints and that float parameters are passed as doubles. or fault on pointer dereferences. Use #define void or #define void int for compilers without the void keyword. or 8. 3. in an attempt to indicate partial compliance with the ANSI C standard. Some libraries attempt to modify and then restore read-only string variables. The libraries are getting better.edu or {rutgers. Mixing styles is worse than using any single bad style. a line with a -. The code may also fail to compile. enums might be better anyway.tektronix}!uwbeaver!june!pardo 2. fault on pointer comparison. such compilers are broken. If you have trouble following any of these standards don't just ignore them.ucsd. or an experienced programmer at your institution. This is still an evolving document. 6. ``Tabstops'' can be blanks (spaces) inserted by your editor in clumps of 2. Programs sometimes won't port because of these broken libraries. 8. Please send comments and suggestions to pardo@cs.in a comment preceding a function is sometimes assumed to be a one-line summary of the function's purpose.ubc-cs.cornell. Unfortunately.'' 9. Use actual tabs where possible. Such automatic type promotion is called widening. Some compilers predefine __STDC__ to be 0. 4. Thus. For older compilers. See the rule about ``don't write around a broken compiler unless you are forced to. 5. Some automated program-analysis packages use different characters before comment lines as a marker for lines with specific items of information. In particular. 7. .washington. Having a style that is consistent (particularly with group standards) is more important than following absolute style rules. Talk with your local guru. fault on pointer creation. Footnotes 1. Many style choices are arbitrary. it is not possible to determine which ANSI facilities are provided. The opinions in this document do not reflect the opinions of all authors. As with any standard. 4.

R. 1978. A. Feldman. O'Reilly & Associates. Ritchie. November 1986. B.02MF.W. J. Glasser. Koenig. J. 1974. Memorandum for File. R. Kernighan and P. Brian W. UNIXSupplementary Documents. Haight. Dallas 1985 Proceedings. 7. C Traps and Pitfalls. ISBN 0-937175-30-7. Andrew R. 3B Processor Common Diagnostic StandardsVersion 1. Lyon dealing with style and portability.A Program for Maintaining Computer Programs. Second Ed. Make -. 11. S. 8. 5521-780329. Prentice Hall 1987. 1988.M. Prentice Hall 1978. 5. Ian Darwin and Geoff Collyer.W. Darwin. 1977. Addison-Wesley. Kernighan and D. Elliott and D. R. 1273770907. 6.'' It is regrettable that there isn't a better solution. 5514-780330. a C Program Checker. Unix Supplementary Documents. E. Tague. The 3B/PDP-11 Swabbing Problem. ISBN 0-13-110362-8. September 14. and T. McGraw-Hill. ISBN 0-20117928-8. Sept 22. The C Programming Language. Flag names may vary. An Overview of C Compilation of Unix User Processes on the 3B. Johnson. Memorandum for File. 9.L. 1978. 11. Can't Happen or /* NOTREACHED */ or Real Programs Dump Core. Mitze. Plauger The Elements of Programming Style.C. March 30. 1978. Mitze. March 29. 2. November 1986.C.01MF. 1989. Pfeffer. ISBN 0-07-034-207-5. 1977. References 1.A. Note that using PROTO violates the rule ``don't change the syntax via macro substitution. This document issued by department 8234 contains three memos by R.L. 12. Checking C Programs with lint. ISBN 013-686494-5.01MF.A. 10. USENIX Association Winter Conference. 3. The Ten Commandments for C Programmers . Memorandum for File. S. 4. C Language Portability.C.W. B. Ian F. Lapin Portable C and UNIX System Programming. Lint.I.10. Second Ed. 1989.

lest grievous harm befall thy program. Converted from troff to HTML and archived by Christopher Lott. If a function be advertised to return an error code in the event of difficulties. Thou shalt not follow the NULL pointer. Thou shalt foreswear. Thou shalt check the array bounds of all strings (indeed. 9. even when thou art convinced that this is unnecessary. for verily its perception and judgement oft exceed thine. the gods shall surely punish thee for thy arrogance.com . for if thou thinkest ``it cannot happen to me''. even though the checks triple the size of thy code and produce aches in thy typing fingers. though this harsh discipline be irksome and the years of its necessity stretch before thee seemingly without end. Thou shalt run lint frequently and study its pronouncements with care. thou shalt check for that code. Thou shalt make thy program's purpose and structure clear to thy fellow man by using the One True Brace Style.Henry Spencer 1. that thy code may be short and readable and thy days pleasant and productive. for thy creativity is better used in solving problems than in creating beautiful new impediments to understanding. 6. If thy header files fail to declare the return types of thy library functions. renounce. 10. 8. yea. and have no commerce with the benighted heathens who cling to this barbarous belief. for surely where thou typest ``foo'' someone someday shall type ``supercalifragilisticexpialidocious''. lest thou tear thy hair out and go mad on that fateful day when thou desirest to make thy program run on an old system. 2. lest they take cruel vengeance upon thee when thou least expect it. and abjure the vile heresy which claimeth that ``All the world's a VAX''. 7. 3. thou shalt declare them thyself with the most meticulous care. Thou shalt study thy libraries and strive not to re-invent them without cause. 5. that the days of thy program may be long even though the days of thy current machine be short. for chaos and madness await thee at its end. Thou shalt cast all function arguments to the expected type if they are not of that type already. Thy external identifiers shall be unique in the first six characters. all arrays). even if thou likest it not. chris "at" lott. 4.

Sign up to vote on this title
UsefulNot useful