Table of Contents Previous Chapter

2. Statement Formatting


Conventions


2.1 Use of Printable Characters & Line Length Limitations


All source code consists of printable ASCII characters, separated into lines by standard control characters, such that lines are no longer than 80 characters. The ANSI C string constant concatenation feature is used to break long strings into manageable pieces.


2.2 Placement of Simple Statements


Simple statements are aligned vertically on independent lines. All simple statements, even null statements, should be placed on an independent line.

COMPLIANT EXAMPLESNONCOMPLIANT EXAMPLE

while (*c++ = getchar())while (*c++ = getchar());
    ;
int main(int argc, char **argv)
    {
    short i;
    scrOpen();
    scrClear();
    plotTrk(i, 'X');
    scrCurs(scrLines - 1, 0);
    scrClose();
    }

A UNIQUE EXCEPTION - widely used with the X11 Toolkit to clarify bookkeepping while avoiding macro side-effects

XtSetArgs(args[i], XtNheight, &height);  i++;
XtSetArgs(args[i], XtNwidth, &width);  i++;

2.3 Standard Indentation


One level of standard indentation corresponds to four columns. Indentation may consist of any combination of tabs and spaces.


2.4 Compound Statement Format


Braces delimiting the body of a compound statement are aligned vertically with each other and with the statements they enclose. The opening brace is on a separate line, and indented one level from the phrase on the preceding line. Braces used to delimit enumerated type definitions, or to initialize arrays or structures, however, may appear on the same line as their contents when the entire statement fits on a single line.

COMPLIANT EXAMPLES

typedef enum { Red, White, Green, Black, Orange, Blue, Yellow } Colors;
long lengths[] = { 22, 44, 3, 25 };
typedef struct
    {
    long length;
    long width;
    } Size;

Size sizes[] =
    {
        { 2, 4 }, { 4, 8 }, { 8, 16 }, { 16, 32 }, 
        { 32, 64 }, { 64, 128 }, { 128, 256 }
    };
typedef struct
    {
    char *process_name;
    char *input_dir;
    char *output_dir;
    short priority;
    unsigned long report_period;
    unsigned long data_freq;
    char *formats[3];
    int input_fmt;
    int output_fmt;
    unsigned long timeout;
    } ProcConfig;
ProcConfig filterProc =
    {
    "DAILY_FILTER", "/usr/local/profiler_hourly", "/usr/local/profiler_daily",
    10, 3600 * 24, 3600,
    { "/usr/local/formats/profiler_fmt", "/usr/local/formats/bufr_fmt", NULL },
    0, 1, 1800
    };

2.5 Control Statement Format


Control statements adhere to the previous rule when the statement body is a compound statement, but the more general convention for control statements is as follows. The body of a control statement and/or control clause is indented one standard indentation from its associated control phrase. Nested control statements have a corresponding nested indentation.

COMPLIANT EXAMPLE NONCOMPLIANT EXAMPLES

while (inventory > 0)while (inventory > 0) {
    {    CountOne();
    CountOne();     inventory--;
    inventory--;               }
    }
                   while (inventory > 0)
                               {
                                   CountOne();
                                   inventory--;
                               }
                              while (inventory > 0) { CountOne(); inventory-- }
                              while (inventory > 0) 
                                  { CountOne(); inventory-- }

switch (a)
    {
    case 0:
        tooLow(a);            switch (base)
        break;                    {
    case 1:                       case 2:   printBinary(value); break;
    case 2:                       case 10:  printf("value=%d\n", value); break;
    case 3:                       case 16:  printf("value=0x%x\n", value); break;
        justRight(a);             default:  printf("Unknown base.\n"); break;
        break;                    }
    default:
        tooHigh(a); 
        break;  
    } 

2.6 Function Definition Format


Braces delimiting a function definition are indented one standard indentation. The entire body of the function definition is indented. This is consistent with control statement formatting.

EXAMPLE OF A COMPLIANT FUNCTION

/*-------------------------------------------------------------------------
** menuSequence()
** This routine handles a sequence of menu interactions with a user.
** 
** Menu *menuPtr;  Reference to initial menu to be displayed.
**
** Returns status of user interaction.
**-------------------------------------------------------------------------*/
MenuStatus menuSequence(Menu *menuPtr)
    {
    int i;
    MenuStatus status = MENU_NORMAL;
    char selector = '\0';
    
    /* This function generates a series of menu screens to a user */
    while (menuPtr != NULL)
        {
        /* Initialize the menu window */
        initMenu(menuPtr);
        /* Generate each menu line */
        for (i=0; i<menuPtr->nlines; i++)
            {
            selector = computeSelector[i];
            addMenuLine(menuPtr->lines[i], selector);
            }
        /* Respond to selections until next menu is requested. */
        while ((choice = queryUser()) != 0)
            {
            if (choice <= menuPtr->maxChoice)
                status = processChoice(menuPtr, choice)
            else
                displayError(choice);
            }
        /* Abort further menus if an exit has been requested. */
        if (status & MENU_EXIT)
            break;
        menuPtr++;
        }
    return status;
    }

COMPLIANT EXAMPLE NONCOMPLIANT EXAMPLES

void shoot_arrow(void)        void shoot_arrow(void)   void shoot_arrow(void)
    {                         {                        {
    int i;                        int i;               int i;
    ...                           ...                  ...
    return;                       return;              return
    }                         }                        }

2.7 Do-While & Typedef Statement Formats


The do-while statement always appears with braces. Both do-while statements and typedef statements containing aggregates require a phrase to appear after the closing brace. These trailing phrases always appear on the same line as the closing brace.

COMPLIANT EXAMPLES

/* Drawing characteristics. */
typedef struct
    {
    Color color;
    int width;
    Pattern pattern;
    } BrushDef;
do
    {
    processPage(ipage); 
    ipage += page_inc;
    } while ((page < last) && (page > 0));

2.8 Nested If Statement Format


Braces are always used when nesting if-else clauses (except when simply concatenating them using the "else if" technique described below), thereby avoiding possible ambiguity in the association between clauses.

COMPLIANT EXAMPLE

if (a >= 0)
    {
    if (a > MaxValue)
        overflow = TRUE;
    else
        a = -1;
    }

2.9 Chained Else If Clause Format


The else if technique shown below is used when chaining if and else clauses. Any number of clauses may be chained. The use of a switch may be more efficient, but has limited means of defining cases.

COMPLIANT EXAMPLE

if (a > 0)
    a = 1;
else if (a < 0)
    a = -1;
else
    a = 0;

2.10 Use of Comma Operators & Delimiters


Commas are not used to concatenate expressions within an executable statement, except within control phrases. Commas are also used within parameter lists and aggregate initializations, enumerated type definitions, and variable declarations.

COMPLIANT EXAMPLES

XtSetArgs(args[i], XtNheight, &height);
x = y = z = 0.0;
typedef enum { APPLE, ORANGE, PEACH, BANANA, PINEAPPLE };
float x, y, z;   /* Projectile coordinates */
for (i=0, ptr=buffer; i < MAX; i++, ptr++) 
    ...

NONCOMPLIANT EXAMPLES

XtSetArgs(args[i], XtNheight, &height),  i++;
XtSetArgs(args[i], XtNheight, &height),  i++;
x = 0.0, y = 100.0, z = 10.0;

Rationale

Source files must be viewable, printable, and editable on a variety of platforms. Use of line lengths greater than 80 columns and/or use of control or unprintable characters (excepting tabs and newlines), are not in keeping with this requirement. Although the use of 132 columns is supported by some machines and editors, it requires use of a small font, and often will not print on standard 81/2 x 11 paper in a standard orientation. Source files must also increasingly be transportable across networks and interpretable by telecommunications software.

Proper function modularity and the ability to break statements over multiple lines eliminate the need for excessively long lines. Concatenation of string constants, a feature available on ANSI C compilers, facilitates the breaking of long strings into lines of appropriate length. The backslash character notation is used to represent unprintable or nonASCII characters in terms of multiple ASCII printable characters. This syntax may be used wherever string or character literals are used in the C language.

Statements are placed one per line so that they may be easily located and manipulated as discrete entities. The free-form nature of the C language does not require any association at all between statements or statement clauses and lines. In practice, however, code is cumbersome to maintain unless there is a strict association between a statement or statement clause and a line. The techniques of indentation and placement of statement clauses on distinct lines work together to allow clauses and statements to be readily located and operated upon as modular elements. The pace with which software may be developed and maintained is significantly affected by the degree of standardization adopted in the form and placement of statements. When developing code for individual use, there may be little need for a programmer to deviate from personal preferences. In a team programming or project-oriented environment, however, software is usually designed and implemented as collections of reusable components. Standardization facilitates this reuse. Programmers accustomed to other languages, particularly FORTRAN, may find some of these placement and spacing rules unusual. Most C programmers in a commercial or production development envioronment promote these or similar conventions as good programming practice.

Braces are used in the C language to group simple statements into compound statements. Compound statements are used in conjunction with control statements, often forming the bodies of such statements. The C compiler ignores white space (carriage returns, spaces, etc.), so there is a great deal of flexibility with regard to the placement of braces and the use of indentation to affect code appearance. The three brace placement conventions depicted below are widely used. The first line of each example contains a control phrase. The statements grouped into each compound statement are indented to distinguish them from subsequent statements not associated with the control phrase.

NONCOMPLIANT STYLES OF BRACE PLACEMENT

if (notEqual && (first > second)) {
    temp = dataPtr[first];
    dataPtr[first] = dataPtr[second];
    dataPtr[second] = temp;
}
if (notEqual && (first > second)) 
{
    temp = dataPtr[first];
    dataPtr[first] = dataPtr[second];
    dataPtr[second] = temp;
}

COMPLIANT STYLE OF BRACE PLACEMENT

if (notEqual && (first > second)) 
    {
    temp = dataPtr[first];
    dataPtr[first] = dataPtr[second];
    dataPtr[second] = temp;
    }

The first style shown is that used by the originators of the C language, and is noted for the drawback that opening braces are sometimes lost within large control statements, causing them to be easily missed when code is rearranged or indentations modified. The second style shown was adopted largely to avoid the likelihood of misinterpretation associated with the original style by emphasizing the presence of braces. The third style shown fits the language more naturally than does the second style, for it logically indents the entire compound statement as a unit, just as a single simple statement would be indented. This third style, which has been promoted for many years by Thomas Plum, the Vice-Chairman of the ANSI C standards committee, has been adopted as an integral part of these conventions.

Note that many of the other conventions within this document are adapted to this style of brace placement so as to give the code a consistent appearance. In this sense, conventions are not independent of each other, even though they are defined independently. Although, as mentioned above, other reasonable conventions exist and are widely used, the need for overall consistency in code appearance precludes allowing more than a single style of brace placement. If more than one style were permitted here, then other conventions would logically have to allow a preferred style for each form of brace placement. The effectiveness of these conventions would then be significantly reduced. Having to mentally map one style into another, or having to reformat code fragments when reusing them, can significantly slow development. One can therefore argue that the particular style used is less important than that there be only a single style used. The adopted style has been selected to promote readability.

Indentation is four columns wide, in the form of spaces and/or tabs. The four column indentation is widely used, and nicely allows a one-half indentation of 2 columns to be used for continuation lines. Many editors (particularly those standard in a UNIX environment) provide automatic indentation with a setable tabstop, making indentation easy to implement. Tabstops can be problematic when automatically expanded to 8 characters by printers and source debuggers. If this is a problem, one may either use spaces for indentation, or may expand tabs to spaces with an appropriate utility (expand on UNIX systems).

Most of the convention definitions associated with control phrases provide examples of how these conventions are used. The following examples further illustrate some of these conventions, and indicate the types of problems avoided through their use.

while ((c = getchar()) != '\0'); printf("Skipped a character: \'%c\'\n", c);

NONCOMPLIANT EXAMPLE

do  
    {
    processPage(ipage);
    ...
    ...
    ...
    ...
   -------page break-------
   --------continuing on next page--------
    ...
    ...
    ...
    ...
    ...
    ipage += page_inc;
    } 
while ((page < last) && (page > 0));

NONCOMPLIANT EXAMPLE

switch (a)
    {
case 0:
    tooLow(a);
    break;
case 1:
case 2:
case 3:
    justRight(a);
    break;
default:
    tooHigh(a); 
    break;  
    } 

NONCOMPLIANT EXAMPLE

if (a < b)
    if (a < c)
        min = a;
else
    min = b;

SAME NONCOMPLIANT EXAMPLE (as interpreted by the compiler)

if (a < b)
    {
    if (a < c)
        min = a;
    else
        min = b;
    }
Braces are therefore always used with nested if-else clauses (as shown below) to avoid this type of problem, and to reduce the general level of ambiguity associated with such statements. It is important to keep in mind that those making modifications to code are generally not those who developed it initially. It is in these situations, where the person making the modification is not intimately familiar with the logic being performed, that a clause may be added having inaccurate indentation. When this happens, the indentation indicates the programmer's interpretation of the logic, which differs from the what the compiler sees.

COMPLIANT EXAMPLE

if (a < b)
    {
    if (a < c)
        min = a;
    }
else
    min = b;

COMPLIANT EXAMPLE

if (a < 10)
    digits = 1;
else if (a < 100)
    digits = 2;
else if (a < 1000)
    digits = 3;
else if (a < 10000)
    digits = 4;
else
    {
    digits = 5;
    overflow = TRUE;
    }
Use of the general indentation rule would generate something like the following:

NONCOMPLIANT EXAMPLE

if (a < 10)
    digits = 1;
else 
    {
    if (a < 100)
        digits = 2;
    else 
        {
        if (a < 1000)
            digits = 3;
        else 
            {
            if (a < 10000)
                digits = 4;
            else
                {
                digits = 5;
                overflow = TRUE;
                }
            }
        }
    }
 
 

Table of Contents Next Chapter