Navigate this site...

C Programming Style Guide

Author: Samuel A. Falvo II
Contact: kc5tja .at. arrl.net
Revision: 1r1
Date: 2007 September 13
Copyright: Copyright 2007 Samuel A. Falvo II. This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.
Status: Published, Personal website.

Contents

Introduction

In any large-scale programming project, the coding conventions dominates how easy the components of a program are to read and maintain. This document aims to provide, for the first time since I started programming in 1980, a concise set of conventions that I follow for my projects, and would appreciate others follow when contributing back to them.

These conventions have evolved over the years, stemming from personal experience, and learning from other masters of the craft. The specific language covered in this document is C, since it's the first non-assembly language I learned (well, not quite true; BASIC was the first, but BASIC doesn't leave much in the way of stylistic freedom like C does). All of my other coding conventions ultimately are based on this document, so it's a good read, even if you are contributing to one of my other, non-C projects.

Acknowledgements

Since my style has been influenced by other parties, I'd like to offer some credit where it's due:

  • Kent Beck, for teaching me the importance of using proper parts of speech in variable, procedure, function, and type names. Kent might actually look at this standards guide, and see a very strong influence from his own Smalltalk conventions guideline.
  • Steve Dekorte, for using _ to indicate positional arguments (e.g., as when telling A to do something to B, you might write A_doSomethingWith_(B); see the examples in this document for clarification). By the way, Steve is another fan of Smalltalk.
  • The framers of the OMG CORBA specification, for standardizing the use of _ (the underscore) to demarcate packages, modules, and interface names. This practice has influenced many others as well, such as the GTK/Gnome project community.
  • Google, Inc., for the TODO(coderNameHere) convention.
  • GNU for standardizing on the split between a function's or procedure's return type and the rest of the definition, allowing effortless and precise location of a function's definition using a tool no more sophisticated than grep, without also locating all of its uses. It also allows the converse (grep "^SomeFunc" versus grep -v "^SomeFunc" | grep "SomeFunc", the latter of which finds its uses, but not its definition).

However, indenting private functions is my innovation, so far as I can tell, because heretofore I've not seen anyone, anywhere, else do it.

Organization

Overall, the organization of this document will be hierarchial. We start with the largest scale structures, and progressively work inwards. Some things were difficult to pidgeon-hole into any one location, so I had to choose what I felt was the most logical place to put them (e.g., variable naming conventions). If you don't find what you're looking for in one section, check the others; I might cover it elsewhere.

Packages

If used, packages are loosely defined as a collections of related modules. They're usually plural nouns, using StudleyCaps. Their name suggests a type of a type. For example, lists, hash tables, and dictionaries are all ways of storing collections of things. Hence, they might appear in a package named Collections.

Packages are more a logical structure, rather than a construct imposed by the C environment. I structure my projects so that each has its own directory root, which I'll refer to as PD throughout the rest of this document. Packages then appear off of the PD root. For example, we might find the Collections package in PD/Collections.

Modules

Broadly speaking, C lacks the concept of a module, as defined by other languages like Haskell, Modula-2, and Oberon. Instead, C makes use of compilation units, which provide a broken approximation of them. We make use of compilation units in a prescribed manner to best emulate modules.

Naming and Project Placement

Modules are named with plural nouns, using StudleyCaps, derived from the primary data type implemented in the module. For example, a module that implements the List type would be named Lists (and be placed in the Collections package most likely). In general, the rule is that one data type is implemented per module. Given a type T, the module's name is the plural form of T.

Every module M should have three files associated with it:

  • M.c -- containing the implementation of the module.
  • M.h -- containing the public interface of the module.
  • M-test.c -- containing the unit tests for M.
  • M-inlines.h -- if, and only if, there are module functions which are to be inlined.

These files are found in the appropriate directory together. For example, to use our List example again, we might find these files:

  • PD/Collections/Lists.c
  • PD/Collections/Lists.h
  • PD/Collections/Lists-test.c
  • PD/Collections/Lists-inlines.h

Referencing Dependencies

When including header files, regardless of where it's being included, be sure to do so from most generic to most specific -- that is, including your module's own headers should occur last. For example, this is considered bad form:

/* in Containers/Lists.c */

#include <Containers/Lists.h>
#include <stdlib.h>
#include <string.h>

Instead, one should prefer this:

/* in Containers/Lists.c */

#include <stdlib.h>
#include <string.h>

#include <Containers/Lists.h>

Generally speaking, there are several broad categories of include files:

  • those that are provided by the C runtime environment,
  • those that are provided by your specific OS or runtime environment,
  • those that are provided by your project's own runtime environment, and,
  • those that are relevant to your module in particular.

Within each category, barring any missing symbol conflicts, try to keep your header files alphabetized. It really does make maintenance that much easier.

When building your project, configure your build system to reference the project's root directory as one of the header roots. Be sure to reference your header files in your source files appropriately!

Header Files

After many years of personal experimentation, I've found the following header organization to be the most readable and maintainable:

As usual, everything should be in alphabetical order unless symbol definition dependencies exist.

Guarding from Multiple Inclusion

Use #ifdef-guards in your header files. The highest-level overview of a header file should look like:

#ifndef PACKAGE_MODULE_H
#define PACKAGE_MODULE_H

/* ... stuff goes here ... */

#endif

The precise symbol to use will depend on your module's placement in the package hierarchy. Use _ (underscore) to replace your system's directory separator character. Regardless of the capitalization of your module's or packages' names, always use ALLUPPERCASEWITHOUTSPACES for each path component. For example:

/* in file /includes/Containers/Lists.h */

#ifndef CONTAINERS_LISTS_H
#define CONTAINERS_LISTS_H

...

#endif

Comments

Header files should have at least some indication of who wrote it, any copyrights or licensing issues, etc. It should appear within the header guard, so that the compiler doesn't waste lexing time on the comments if it doesn't have to.

#ifndef CONTAINERS_LISTS_H
#define CONTAINERS_LISTS_H

/* Containers/Lists.h
 * Release 20070914
 *
 * Copyright (c) Samuel A. Falvo II
 * See docs/LICENSE for rights.
 *
 * This file implements a singly-linked list implementation.  If you
 * are looking for a doubly-linked list implementation, see
 * Containers/DList.h.
 *
 * This module is intended to be used by other modules, and not by the
 * user directly.  For safe, Lisp-like lists, see Containers/SLists.h
 * instead.
 */

...

#endif

Headers Including Headers

If your module makes use of other modules, reference them via #include directives in the interface header of the module. For example, given a module M that depends on modules N and O:

#ifndef PACKAGE_M_H
#define PACKAGE_M_H

#include <AnotherPackage/N.h>
#include <AnotherPackage/O.h>

...etc..

Where possible, the header files should be arranged alphabetically by module name.

To speed up the compile process, make use of your compiler's support for precompiled header files. I wish I had better suggestions than this, but C is fundamentally broken in this aspect, and cannot be fixed without breaking source compatibility with existing software.

Inline Functions

If you need inline functions for some reason, please separate them into a M-inlines.h file. Never include M-inlines.h from within M.h.

Typedefs

All typedefs should be, as much as possible, arranged in a common part of the header file, and arranged alphabetically by the synonym defined. For example:

typedef struct Accessor Accessor;
typedef struct List     List;
typedef struct Node     Node;

/* Note the exception here, due to symbol definition dependency */
typedef void Callback(Accessor *, List *, Node *, void *, int);

Constants and Enumerations

Unless it is highly inconvenient to do otherwise, do not use the C preprocessor for defining constants. Instead, make use of enumerations. Enumerations are broken in C in one respect: enums, unlike structs and unions, do not provide a namespace. Therefore, be sure to name your enumerated constants distinctly, as you would with #define constants.

enum ListAccessMode {
  LISTS_LAM_startFromBeginning,
  LISTS_LAM_startSomewhereInTheMiddle,
  LISTS_LAM_startFromTheEnd,
  LISTS_LAM_pickRandomly
};

Flags should always have both bit number and the field mask set:

enum ListStates {
  LISTS_LSB_hasBeenArchived = 2,
  LISTS_LSB_hasBeenModified = 1,
  LISTS_LSB_isEmpty = 0,

  LISTS_LSF_hasBeenArchived = (1L << LISTS_LSB_hasBeenArchived),
  LISTS_LSF_hasBeenModified = (1L << LISTS_LSB_hasBeenModified),
  LISTS_LSF_isEmpty = (1L << LISTS_LSB_isEmpty),
};

Use of C preprocessor macros to automate this process is permitted, but no preferred mechanism has been settled upon in my earlier sources. I'll therefore leave the precise set of macros undefined for now.

Try not to use bit-fields in structures for the purposes of defining publicly accessible flags, as there is no standardized method of guaranteeing bit positions. For private use, however, bit-fields are prefered.

Each enum should have a corresponding typedef, to save the coder from having to constantly type enum in the source code (such keywords also impede source readability in most cases anyway).

Where possible, define your symbols in alphabetical order. This is not always possible, especially when releasing a new version of a module where backward compatibility is important. In this case, define each symbol alphabetically first by generation, then by symbol name. It would be nice to identify when the flag was introduced, to save the programmer from having to review SCM logs. For example:

enum ListStates {
  LISTS_LSB_hasBeenArchived = 2,
  LISTS_LSB_hasBeenModified = 1,
  LISTS_LSB_isEmpty = 0,

  /* Version 20070914 */
  LISTS_LSB_advancedMode = 3,
  LISTS_LSB_hasACL = 4,
  LISTS_LSB_readOnly = 5,


  LISTS_LSF_hasBeenArchived = (1L << LISTS_LSB_hasBeenArchived),
  LISTS_LSF_hasBeenModified = (1L << LISTS_LSB_hasBeenModified),
  LISTS_LSF_isEmpty = (1L << LISTS_LSB_isEmpty),

  LISTS_LSF_advancedMode = (1L << LISTS_LSB_advancedMode),
  LISTS_LSF_hasACL = (1L << LISTS_LSB_hasACL),
  LISTS_LSF_readOnly = (1L << LISTS_LSB_readOnly)
};

Structures and Unions

Structures (and unions) are defined in alphabetical order by structure name. Structure names, like all type names, are expressed in StudleyCaps, and should take the form of a singular noun. The fields contained within it should always be alphabetized by name, compatibility issues notwithstanding of course.

/* We disobey the alphabetization rule here because the implementation
 * will depend on the precise memory layout.  This list structure is
 * inspired by that used under Commodore-Amiga's exec.library.
 */
struct DList {
  Node *head;
  void *unusedNullPtr;
  Node *tail;
};

struct DNode {
  void *datum;
  Node *next;
  Node *previous;
};

References to other enums, structures, or unions should not include the enum, struct, or union keywords. Each structure or union also should have a corresponding typedef.

Declaring structures defined in other modules should always be by-reference (e.g., using a pointer). Unless you have good reason to, never declare a structure by-value. Otherwise, you run the risk of having your module break if the dependency is recompiled (e.g., in object oriented programming terms, this is the classic "fragile base-class" syndrome).

Function Prototypes

Function prototypes are, like structures, arranged alphabetically by name. Although grouping by generation isn't necessary, it is strongly encouraged, so as to see when a function was introduced without having to waste time browsing the SCM tool, if you even have access to such records.

DList *DList_alloc(void);
void   DList_append_(DList *, Node *);
Node  *DList_head(DList *);
void   DList_init(DList *);
void   DList_prepend_(DList *, Node *);
Node  *DList_removeHead(DList *);
Node  *DList_removeTail(DList *);
Node  *DList_tail(DList *);

/* Release 20070914 */
int    DList_forEachNodeDo_(DList *, Accessor *);
int    DList_isEmpty(DList *);
int    DList_length(DList *);

Implementation Files

Implementations (.c) files should take the following form:

You'll notice that the only significant difference from the structure of header files, from this level of consideration, is the scope in which constructs are defined. Since applications should never #include a .c-file, it follows that typedef, enum, struct, and union definitions should not be visible to other modules.

The rules governing dependencies, typedefs, constants, structures/unions, and prototypes are all the same as for headers; they therefore will not be discussed further here.

Whitespace

All top-level entities, be they functions, structures, et. al. should have two blank lines separating them. All other entities should be spaced with individual blank lines. For example:

#include <stdio.h>


void
print_(int aNumber) {
  printf("The number is: %d\n", aNumber);
}


int
main(int argc, char *argv[]) {
  int j;

  for(j = 0; j < 100; ++j) {
    print_(j);
  }
}

Notice that there are two lines separating the includes from the start of the code; likewise, two lines separate the functions. Inside each function, however, major blocks are separated by only one line.

Functions and Procedures

Function names should be comprised of two parts, separated by an underscore: first is the module prefix, and second, what it is the function actually does. This is done because C lacks type-specific name spaces or generic functions. It's the best way to disambiguate similarly named functions.

The module name follows the normal module naming rules (noun expression, StudleyCaps, etc.). However, the function name itself follows camelCaps. Whether it is named to be an imperative or not depends on whether it is a true function or a procedure.

A function, because it represents only a pure computation, need not have an imperative name; instead, like a variable, it can be named for what the function returns. For example, sin(), List_length(), and File_size().

Procedures, however, necessarily inflict a change of state. This should be reflected in its name; you wouldn't invoke the procedure except to instruct the computer to do something, so it's best if it has an imperative name, such as List_append_(), or Window_moveTo_(), etc.

As with the prototypes, all public functions are arranged alphabetically with each other, and take the following form:

ReturnType
Module_functionName(parameters) {
  ...
}

Notice that the return type and the procedure name are on separate lines, both aligned to column zero. For functions or procedures which are private to a module, mark them as static, and indent it one or two levels so as to make them stick out more. There is no need to use the module prefix convention for internal functions, but using underscores to identify positional arguments should still be followed:

    static int
    squareOf_(int a) {
      return a*a;
    }


int
sumOfSquaresOf_and_(int a, int b) {
  return squareOf_(a) + squareOf_(b);
}

Where possible, however, keep the parameters on the same line as the function's name. If the parameter list doesn't fit on the same line, then treat the function header as a block-structured declaration:

int
sum_with_and_and_and_(
  int a,
  int b,
  int c,
  int d,
  int e
) {
  return a+b+c+d+e;
}

Underscores in Function Names

In Smalltalk, the colon is used to indicate a keyword that accepts a parameter. For example:

aLabel createWithTitle: "Hello world!" andForeground: #green.

Of course, C doesn't allow symbols to be constructed this way, but it's pretty clear to see how the Smalltalk code is vastly easier to read than something like:

creatlabl(aLabel, "Hello world!", COLORS_GREEN);

Smalltalk, will convert the message send operation into a function call like this (not really, but we're talking on a conceptual level here):

createWithTitle:andForeground:(aLabel, "Hello world!", #green).

That is, it preserves the colons as they are an integral part of the function's name. The function's name is said to be the message's selector (since it selects which operation the object is to perform).

I prefer Smalltalk-inspired selectors because it is a powerful technique in writing software which is concurrently human and machine readable. It also helps the coder to identify opportunities for factoring your code, by forcing you to label concepts with precision.

Since, in C, you cannot use colons in a function's name, we choose to use underscores instead. So, we'd write the above call as:

Label_createWithTitle_andForeground_(aLabel, "Hello world!", COLORS_GREEN);

Note that there is precisely one underscore per parameter given in the list. The first underscore not only separates the module's name from the rest of the function's name, but it also doubles as the slot in which the first parameter goes. It's perhaps best to think of it in a manner similar to printf(), where you use %-notation to indicate slots in which parameters, taken in order from left to right, are filled in. So, the above can be read:

Label aLabel, create (something) with a title "Hello world" and a
foreground of green.

Observe that the names of functions can be pretty long. Observe, also, that the function name itself is documenting what is being performed in the function; hence, it significantly reduces the need for comments. However, please attempt to keep the number of arguments to a function reasonable. If your function or procedure requires more than four parameters (one "direct object" and three procedural parameters), seriously consider refactoring the function into smaller pieces.

Parameter Passing

Parameters to C functions are inputs, outputs, or both. Where possible, keep your inputs to a function leftmost on the argument list. Keep your outputs right-most. Parameters which are both input and output are strongly discouraged; however, if they are needed, try to keep them in the middle.

In non-trivial functions, I advocate the use of const for input-only parameters, particularly involving pointers. I've been lax in doing this myself, however. It is very hard to break years of a bad habit.

Most often, your modules will be implementations of some abstract data type. Instances of that type should be referenced using the very left-most argument. For example:

List_append_toList_(aNode, toThisList);

is bad form. Instead, this is preferred:

Node_appendToList_(aNode, toThisList);

or better yet:

List_appendNode_(toThisList, aNode);

Variables and Fields of Structures and Unions

A variable name (of which I also consider structure fields, etc.) should be a singular or plural noun expression, describing what it actually is for or is referencing, and be in camelCaps. For example, a table might consist of a list of rows:

typedef struct Table Table;

struct Table {
  ...
  List *rowList;
  ...
};

Definite or indefinite articles are encouraged where they'd make sense in an expository manner:

int
Table_numberOfRows(Table *theTable) {
  Node *aRow = List_head(theTable -> rowList);
  int numberOfRows = 0;

  while(aRow != NULL) {
    ++numberOfRows;
    aRow = Node_next(aRow);
  }

  return numberOfRows;
}

Where possible, and I admit that C sometimes makes this hard, define local variables in a scope as local as possible. If we can make the observation that global variables are considered harmful, then we can extend this philosophy to relative scopes -- variables defined in an inner scope are preferable to variables defined in an outer scope.

Where possible, combine the initialization of the variable with its declaration. See Table_numberOfRows() above for an example.

Try hard to write your functions so that there is one, and only one, assignment per variable. Note that parameters to a function are assigned at the call-site, and that counts. Re-assignments of variables should only occur when updating loop state.

General Miscellania

These are some things which I found particularly hard to classify. They are more petty, I suppose, so I don't nearly place as much priority on these suggestions as I do in the previous sections.

Pre- Versus Post-Increment/Decrement

In C, you can use the ++ (or --) operator in front, or behind, a variable to pre- or post-increment the variable. This is most often used in situations like:

int
strlen(const char *c) {
  const char *start = c;
  while(*c++ != 0);
  return c - start;
}

In most cases, the compiler would recognize these operations and emit optimized code. The *c++ would probably be converted to a post-increment addressing mode of some kind, thus off-loading the requirement for incrementing c to the microprocessor's effective address logic. Likewise, length++ would be compiled as a simple increment, since its original value is not used.

However, modern, commercially available/successful processors such as the PowerPC and Intel IA-32 architectures are not optimized for post-increment or -decrement operations. It is far less expensive to make use of pre-increment/decrement operations.

int
strlen(const char *c) {
  const char *end = c-1;
  while(*++end != 0);
  return end - c;
}

The resulting code is generally faster on compilers which aren't so smart. However, since this is entering the realm of optimization, where what makes most sense from a code legibility point of view isn't always so clear, it is a good idea to interject some comments in the appropriate places.

How Big is an Integer?

When using integer types, never rely on the precise bit-widths for int or long. It's safest to just assume that int is a 16-bit wide variable. If you need longer, you should include some typedefs that encapsulate domain-specific knowledge about the underlying platform (e.g., exposes (s|u)int(16|32|64|...) typedefs for signed/unsigned integers of 16-, 32-, or 64-bit widths).

Your Audience

Functions and procedures should be self-documenting; it should be readily apparent from inspection of the source code two things:

  • The function name tells what it actually does, and,
  • The definition tells how it does it.

However, in some cases, it might not always be possible to do this.

For variables, functions, or procedures which are hard to write expositively without seriously affecting some delivery requirement (usually involving optimizations for speed), it will be necessary to precede it with a comment that explains what the thing does. If argument usage isn't obvious from context, then detailing the inputs and outputs is required as well. Formatting the comment block in a machine parsable format, such as that expected by Doxygen, is a big plus.

You Are Not Expected to Understand This

In source files with non-trivial or highly optimized code, where well-factored code results in code which is too slow, it is common to see comments saying something to the effect of:

/* you are not expected to understand this code. */

These kinds of comments are strictly forbidden. If you're going to be so lazy as to not even include a reference to a description of the algorithm or optimization you're using, then don't bother contributing. You're just wasting the next maintainer's time.

Even better would be to include a synopsis of the algorithm or optimization, so that the maintainer doesn't have to waste time searching the web for algorithms which look similar, but aren't the same as, what you're using.

Note to Self

You should use TODO comments for code which is temporary or which will require attention later on. The format should be TODO(C) for some coder C. The format of the username is up to the specific project's maintainers. I like to use my ham radio callsign (kc5tja) or my first initial and last name (sfalvo).

/* TODO(sfalvo): Fix this bug tomorrow. */
someBuggyCodeHere();

Braces

Braces should be K&R-style. In years past, I used to be an ardent supporter of ANSI-style brace placement. For example:

int main(int argc, char *argv[])
{
  printf( "Hello world!\n" );
  return 0;
}

I've performed some experiments between K&R and ANSI brace placement. It really is much faster to use K&R placement. Editors also seem to support the K&R brace placement better as well. The reduction in legibility that it produces is more than made up for by well-named functions and variables. Below is a rather non-trivial example of some C code following the conventions in this document:

int
Buffer_encodeUsingCobsTo_(Buffer *input, Buffer *output) {
  int chunkPosition, inputIndex, numberOfBytesEncoded;

  if(Buffer_size(output) < 3) return ERR_BAD_BUFFER;
  if(Buffer_size(input) >= Buffer_size(output)) return ERR_BAD_BUFFER;
  if(Buffer_isReadOnly(output)) return ERR_READONLY;

  chunkPosition = 0;
  inputIndex = 0;
  numberOfBytesEncoded = 1;

  /* See http://www.stuartcheshire.org/papers/COBSforSIGCOMM/
   * to see why and how the procedure below works.
   */
  while(inputIndex < Buffer_size(input)) {
    b = Buffer_byteAt_(input, inputIndex);
    if(b == 0) {
      chunkPosition = numberOfBytesEncoded;
    } else {
      Buffer_incrementByteAt(output, chunkPosition);
      Buffer_setByteAt_to_(output, numberOfBytesEncoded, b);

      if(Buffer_byteAt_(output, chunkPosition) == 254)
        chunkPosition = ++numberOfBytesEncoded;
    }
    ++numberOfBytesEncoded;
  }
  Buffer_nullTerminateAt(output, numberOfBytesEncoded);
  return numberOfBytesEncoded+1;
}

Spaces

Years ago, I've advocated using lots of spaces in parameter lists, or pretty much anything involving bracketing of some kind. I've changed my position on this (also due to my timing experiments); I now prefer to use no spaces:

if(someConditionIsTrue)
while(Blah_isTrue(aBlah))

However, I still advocate spaces between infix operators, and after commas:

result = M_procedure_with_and_and_((a + b + c), f, g, "hijkl");

Condensing spaces like this doesn't really affect the legibility of the line, and even may provide enough room to write a construct out horizontally.

Write Horizontally Where Possible

Humans like to read from left to right (or right to left, depending on your written language heritage). Except for many Asian-descended languages, it is rare to find people who are more familiar with a vertical script. Therefore, in the interests of writing software expositively, effort should be expended in writing in as horizontal a manner as it makes sense to.

If a conditional statement has only one statement in its consequent, then it should appear to the right, not below, the construct. For example:

/* Bad form */

if(Object_hasProperty_(anObject, "color"))
  Object_setColorTo_(anObject, "red");

/* Preferred */

if(Object_hasProperty_(anObject, "color")) Object_setColorTo_(anObject, "red");

This may not always be feasible, of course. If the consequent is just too long to fit with the conditional, then splitting to the next line is of course recommended:

/* Unless you have a 200-character wide display, this is likely
 * going to have to fit on two lines.
 */
if(Object_hasProperty_(anObject, "color"))
  printf("The object is colored %s", Object_getProperty(anObject, "color"));

If the conditional has an else-clause, it follows the same basic rules.

/* Bad form */

if(Object_hasProperty_(anObject, "color"))
  Object_setColorTo_(anObject, "red");
else
  printf("Color not found.\n");

/* Bad form */

if(Object_hasProperty_(anObject, "color")) Object_setColorTo_(anObject, "red");
else
  printf("Color not found.\n");

/* Bad form */

if(Object_hasProperty_(anObject, "color"))
  Object_setColorTo_(anObject, "red");
else printf("Color not found.\n");

/* Good form */

if(Object_hasProperty_(anObject, "color")) Object_setColorTo_(anObject, "red");
    else printf("Color not found.\n");

Note that the else-clause is indented by two levels of indent.

If either the consequent or alternate clause of a conditional requires more than one statement, then all bets are off -- use the traditional, vertical style of coding:

if(Object_hasProperty_(anObject, "color"))
  Object_setColorTo(anObject, "red");
else {
  printf("Color not found; making one.\n");
  Object_createProperty_(anObject, "color");
  Object_setColorTo(anObject, "green");
}

This goes for looping constructs as well (again, line-length permitting):

/* These would be preferable if your project's accepted line lengths
 * were in the vicinity of 160 characters.
 */

for(current = 0; current < Buffer_size(b); ++current) sum += Buffer_byteAt_(b, current);

while(!done) done = Window_processInputEvents(aWindow);

do { Terminal_newLine(aTerminal); } while(Terminal_currentLine(aTerminal) < Terminal_height(aTerminal));

/* However, if you need more than one statement in the loop body... */

do {
  Terminal_newLine(aTerminal);
  Terminal_blankLine(aTerminal);
} while(Terminal_currentLine(aTerminal) < Terminal_height(aTerminal));

Short Variable Names

Single-letter and other "math-like" local variable names are permitted provided the entirety of their enclosing scope is less than 25 lines in size, and their meaning is so patently obvious that comments aren't necessary to describe them to someone who has never seen the code before. The idea is to maintain enough visual context to figure out what they are, and why they're important, instantly at a glance.

Otherwise, avoid them like the plague. I find my software is vastly easier to maintain in the longer term if I use fully descriptive variable names. Yes, this means using "fooIndex" instead of just "i" if necessary.