Author: | Raphael ‘kena’ Poss |
---|---|
Date: | July 2014 |
Contents
This document describes how to format and layout C code when preparing assigments to be graded. This standard exists to streamline the work of teaching assistants and to avoid common mistakes when programming in C.
Note that in the text below, all “bad” examples are actually valid C code: they are functionally equivalent to the corresponding “good” example to the left. However, they are called “bad” because their style does not follow the standard.
For the 3rd year Systems Programming course at the Vrije Universiteit, academic year 2014-2015, adherence to this standard is mandatory.
The grading process will go as follows:
does the submission follow the rules in File system layout below?
no: reject from grading. Yes: proceed to step 2.
does the C code follow the standard Code style below?
no: reject from grading. Yes: proceed to step 3.
does the code compile without errors or warnings as per Compiler warnings and Build rules below?
no: reject from grading. Yes: proceed to step 4.
grade the assignment using the assignment's criteria, constrained by the section Run-time behavior below.
No exceptions!
source trees must be submitted as a tarball compressed using either gzip or bzip2 (.tar.gz or .tar.bz2).
submitted archives must expand to a directory named after the name of the archive without extension (ie. foo.tar.gz must expand to foo/).
the top-level directory must contain a file named “AUTHORS” (capitalized, with no extension), containing the name(s) and student number(s) of the project authors, one per line.
Note
The student numbers are extracted automatically using a regular expression. Do not enter data that would match the regular expression unintendedly.
the provided tree must not contain any compiler output (.o, .i, .s etc.) nor temporary files (*.bak, *~, #*#, etc.).
all names (within code, but also file or directory names!) must be either fully expressive or use a well-known short mnemonic.
Abbreviations are tolerated as long as they shorten the code significantly without loss of meaning.
Preprocessor macros names and enum values must be fully capitalized; preprocessor macro parameters must be simply capitalized; all other identifiers must be in small letters. Words must be separated by underscores.
// Good: #define XFREE(Var) \ do \ { \ if (Var) \ free(Var); \ } \ while (0) #define MAX_LINE_SIZE 10 enum t { FIRST = 0, SECOND = 1 }; struct my_list; enum some_enum; typedef int custom_t; void compute_some(); |
// Bad: #define xfree(VAR) \ do \ { \ if (VAR) \ free(VAR); \ } \ while (0) #define max_L_sz 10 enum t { First = 0, second = 1 }; struct myList; enum SomeENUM; typedef int Custom_t; void computesome(); |
typedef names must be suffixed with “_t”.
// Good: typedef unsigned uint_t; typedef struct point { int x; int y; } point_t; |
// Bad: typedef unsigned uint; typedef struct point { int x; int y; } point; |
the name of global variables (when at all necessary, see next section), must start with the prefix “g_”.
code may not contain unprintable ASCII characters.
code must only use ASCII space (code 32) and newline characters (code 10) as white space; in particular ASCII tabs (code 9) must not be used, nor the DOS/Windows carriage return (code 13).
all code must fit within 80 columns.
code must not contain trailing whitespaces.
the body of a function definition can contain at most 25 lines of code (opening and closing braces excluded).
function bodies must not contain any comments; comments that explain a function should be placed before the function definition.
blocks must be indented; the same indentation width must be used consistently throughout a submission, with a minimum of 2 spaces.
// Good: void foo(void) { while (1) { printf("hello\n"); } } |
// Bad: void foo(void) { while (1) // 1 spaces = too small { // 5 spaces not consistent // with 1 used above printf("hello\n"); } } |
opening and closing braces for statement blocks must always appear on a line of their own, aligned with one another.
// Good: void foo(void) { while (1) { printf("hello\n"); } } |
// Bad void foo(void) { while (1) { printf("hello\n"); } } |
the opening brace for a struct, union or enum declaration must appear on a line of its own; the closing brace must be the first token on a line, aligned with the opening brace; if a closing brace is followed by a declarator, then the declarator must begin on the same line.
// Good: struct point { int x; int y; }; typedef enum { FALSE = 0, TRUE = 1 } bool_t; |
// Bad struct point { int x; int y; }; typedef enum { FALSE = 0, TRUE = 1 } bool_t; |
a control structure (if, for, etc.) must always be followed by a new line.
// Good: if (cp) return (cp); if (cp) { return (cp); } |
// Bad: if (cp) return (cp); if (cp) { return (cp); } |
at most one variable can be declared by line.
// Good: int foo(int x, int y, int z) { int u; int v; u = x + y; v = y - z; return u * v; } |
// Bad: int foo(int x, int y, int z) { int u, v; u = x + y; v = y - z; return u * v; } |
all variable declarations within a scope must appear at the start of the scope.
// Good: int foo(int x, int y, int z) { int u; int v; u = x + y; v = y - z; return u * v; } void bar() { int i; for (i = 0; i < 10; ++i) { int j; printf("%d\n", i); j = i - 1; printf("%d\n", j); } } |
// Bad: int foo(int x, int y, int z) { int u; u = x + y; int v; v = y - z; return u * v; } void bar() { for (int i = 0; i < 10; ++i) { printf("%d\n", i); int j = i - 1; printf("%d\n", j); } } |
the declarations must be separated from the first statement with a blank line.
// Good: int foo(int x, int y, int z) { int u; int v; u = x + y; v = y - z; return u * v; } |
// Bad: int foo(int x, int y, int z) { int u; int v; u = x + y; v = y - z; return u * v; } |
all declared identifiers in a group of declarations must be aligned on the same text column within a scope, using spaces between the "declaration specifiers" and the "declarator" parts.
// Good: int x; char *p; long long y; void (*z)(int, int); struct t { char u; char v; }; |
// Bad: int x; char* p long long y; void (*z)(int, int); struct t { char u; char v; }; |
variable initializations must be separated from variable declarations, except when the variable is static where there must always be an initializer in the declaration:
// Good: int x; static int y = 1; x = 1; |
// Bad: int x = 1; static int y; |
all keywords with arguments must be followed by exactly one space before their argument(s).
// Good: if (...) for (...) return ... x = sizeof (...) |
// Bad: if(...) for(...) return(...) x = sizeof(...) |
all binary operators except the comma, and the ternary (“?:”) operator, must be separated from their operands with exactly one space (when the operand is on the same line).
// Good: x = 3; f(x) + g(y) f(x) && g(y) for (i = 0; i < 10; ++i) |
// Bad: x=3; f(x)+g(y) f(x)&&g(y) for (i=0; i<10; ++i) |
unary operators must precede or follow their operand without intervening white space.
// Good: x = ++i; y = *p++; z = !x; |
// Bad: x = ++ i; y = * p ++; z = ! x; |
an opening parenthesis “(” or square bracket “[” must be followed by the following token without intervening whitespace; conversely, a closing parenthesis “)” or square bracket “]” must follow the preceding token without intervening whitespace.
// Good: x = f(y); z = x[y]; |
// Bad: x = f( y); z = x[y ]; |
a function expression or preprocessor macro name must be followed by the opening parenthesis of the argument list without intervening white space.
// Good: f(); y = (*g)(x); z = f(x, y); |
// Bad: f (); y = (*g) (x); z = f (x, y); |
remember that exit is a function but return and sizeof are keywords.
// Good: if (!cp) exit(1); return (cp); |
// Bad: if (!cp) exit (1); return(cp); |
commas and semicolons must follow the preceding token without whitespace, and must be separated from the next token (if any) with a white space.
// Good: z = x; w = f(x, y); u = g(x); for (x = 0; x < 10; ++x) return; |
// Bad: z = x ; w = f(x,y); u = g( x); for (x = 0 ;x < 10 ;++x) return ; |
the switch and goto statements must not be used.
All C code must compile without errors or warnings when the following compiler flags are provided:
-std=c11 -Werror -pedantic -Wall -Wextra -Wformat=2 -O -Wuninitialized -Winit-self -Wswitch-enum -Wdeclaration-after-statement -Wshadow -Wpointer-arith -Wcast-qual -Wcast-align -Wwrite-strings -Wconversion -Waggregate-return -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wredundant-decls -Wnested-externs -Wno-long-long (for Clang only:) -Wglobal-constructors -Wshorten-64-to-32
the command:
cc -I. -c *.[cS]
must always complete successfully (with all flags described in Compiler warnings above). In particular, all source files must be present at the toplevel directory, and no invalid/incomplete source files must remain laying around.
if a Makefile is submitted, then:
if the submission includes a program named “configure”, then this program must be executable without argument; in addition, it will be executed exactly once before testing for Makefile rules as described above.
Copyright © 2014, Raphael ‘kena’ Poss. Permission is granted to distribute, reuse and modify this document and other documents for the Systems Programming course by the same author according to the terms of the Creative Commons Attribution-ShareAlike 4.0 International License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/4.0/.