Style Guide

When you are modifying an existing program, the first and foremost rule of good coding style is that the style of your code, e.g., its indentation, should match the style of the surrounding code. In effect, it should not be obvious to a reader where different people have edited the code. Also, keep in mind that if you consistently indent your code, it will make it easier for someone else (i.e., the graders) to understand your code.


Clang-format

Each of the assignments includes a format rule in the Makefile. You can reformat your code to mostly conform to this style guide by running:

        make format

This will run clang-format to format the code. The VSCode C/C++ extension also uses clang-format to format C code. So, you can also format your code directly within VSCode — using Ctrl+Shift+I, for example. Note that you likely were prompted to install this extension the first time you opened a C file, if it was not already installed.

Note that while clang-format brings the code more in line with the style guide, you still need to read and understand the guide. It is your responsibility to perform whatever additional formatting is needed to conform with the guide below.

Specific Guidelines

Any comment that does not appear on the same line as code must consist of one or more complete sentences.

     /*
      * VERY important single-line comments look like this.
      */

     // Most single-line comments look like this.

     /* A single-line comment can also look like this. */

     /*
      * Multi-line comments look like this.  They should consist of real
      * sentences.  Fill them so that they look like real paragraphs.
      */

Include directives come first. More precisely, if operating system header files (i.e., sys/*.h) are used, they come first, followed by a blank line. Include directives for C standard library header files come next. These include directives should be sorted alphabetically by file name. If application header files (e.g., csapp.h) are used, they come last, preceded by a blank line.

     #include <sys/types.h>  // Operating system files in angle brackets

     #include <assert.h>     // C standard library files in angle brackets
     #include <math.h>
     #include <stdio.h>
     #include <string.h>

     #include "csapp.h"      // Application files in double quotes

Major structures should be declared near the top of the file in which they are used, or in separate header files if they are used in multiple source files.

Try to align the field names and any comments describing them in the structure definition.

     struct foo {
             struct foo   *next;    // List of foo
             struct mumble amumble; // Description of amumble
             int           bar;     // Description of bar
     };

All functions are prototyped somewhere, either in a header file or a source file.

Function prototypes for private functions (i.e., functions not used elsewhere) go near the top of the source file. Private functions should be declared static.

All functions should have a requires/effects comment that states the requirements of the function and briefly describes what the function does. As a special case, the requires/effects comment before the "main" function should describe what the program does.

     /*
      * Requires:
      *   Nothing.
      *
      * Effects:
      *   If the "-t" option is specified on the command line, then test code is
      *   executed.  Otherwise, a simple message is printed to standard
      *   out.  Upon completion, the program always returns 0.
      */
     int
     main(int argc, char *argv[])
     {
             long  num;
             int   ch;
             char *ep;

The function type should be on a line by itself preceding the function. The opening brace of the function body should be on a line by itself.

     static char *
     function(int a1, int a2, float fl, int a4)
     {

There is a space after keywords (if, while, for, return, switch).

There are no spaces after function names. Commas have a space after them. Semicolons not at the end of a line have a space after them. There are no spaces after `(' or `[' or preceding `]' or `)' characters.

             error = function(a1, a2);
             if (error != 0)
                     exit(error);

Unary operators do not require spaces, but binary operators do. Do not use parentheses unless they are required for precedence, or unless the statement is confusing without them.

             a = b->c[0] + ~d == (e || f) || g && h ? i : j >> 1;
             k = !(l & FLAGS);

Each level of indentation should consist of 8 character positions. By default, in most text editors, including nano, a tab character skips ahead to the next tab stop, which is the next character position that is a multiple of 8. Thus, you may use the tab character instead of multiple spaces to easily indent your code.

Statements that would exceed 80 characters must be wrapped. In other words, the statement should occupy multiple lines. The continuation lines of a wrapped statement are indented an extra four character positions over the line being wrapped. If you have to wrap a long statement, put the operator at the end of the line.

             while (cnt > 20 && this_variable_name_is_too_long &&
                 ep != NULL)
                     z = a + really + long + statement + that + needs +
                         two + lines + gets + indented + four + spaces +
                         on + the + second + and + subsequent + lines;

Closing and opening braces go on the same line as the keyword (if, else, while, for, switch). Braces that are not necessary may be left out.

             if (test)
                     stmt;
             else if (bar) {
                     stmt;
                     stmt;
             } else
                     stmt;

When defining variables in functions, there are two styles: classic and modern. In the classic style, all variables are defined at the beginning of the function. In contrast, in the modern style, a variable is defined when it is first used. You may use either style.

When using the classic style, define variables sorted by the size of the type, then in alphabetical order. Note that this means that arrays of and pointers to a particular type should be grouped with objects of that type. Defining multiple variables per line is okay. However, the line must not exceed the 80 character limit. Repeat the type on the continuation line.

             struct a_32_byte_struct alfa, *bravo;
             double                  charlie, *delta;
             int                    *echo, foxtrot, **golf;
             char                    hotel, *india, juliett, kilo[16], lima;
             char                    mike, november, oscar, **papa;

When using the modern style, both the variable's definition and the first assignment to the variable take place in the same statement. Try to minimize the scope of the variable.

     long
     function(long array[], int length)
     {

             long sum = 0;
             for (int i = 0; i < length; i++) {
                     long multiplier = random();
                     sum += multiplier * array[i];
             }

Portions of this style guide have been borrowed from STYLE(9) from the FreeBSD Kernel Developer's Manual. The original copyright notice is reproduced below:

Copyright 1992-2012 The FreeBSD Project. All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are
permitted provided that the following conditions are met:

   1. Redistributions of source code must retain the above copyright notice, this list of
      conditions and the following disclaimer.

   2. Redistributions in binary form must reproduce the above copyright notice, this list
      of conditions and the following disclaimer in the documentation and/or other materials
      provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE FREEBSD PROJECT ''AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FREEBSD PROJECT OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

The views and conclusions contained in the software and documentation are those of the
authors and should not be interpreted as representing official policies, either expressed
or implied, of the FreeBSD Project.