C Style Guide

Under Construction: Consider this content a preview of the real thing which is coming soon (hopefully).

WARNING: Large portions of the code base do not comply with this style guide. The violations will be remedied in time. For those so motivated, this is an excellent opportunity to create your first pull request.

Any fool can write code that a computer can understand. Good programmers write code that humans can understand. - Martin Fowler

Without exception, a preliminary task during the inception of a software project should be to either adopt or create a style guide. It’s difficult to overstate the importance of this. The most obvious advantage is readability. Consistent formatting and naming guidelines reduce the reader’s requisite cognitive load. Beyond readability, they enforce conceptual congruence. Defining preferred approaches to common tasks reduces bugs and creates a consistent experience for both end users and developers. Stated differently, style guides ensure that studying a single portion of the code provides insight into the rest of the code.

A style guide is a also a form of documentation. They record important decisions for posterity. When there are disagreements, the style guide is the source of truth. However, it’s important to avoid the common blunder of becoming beholden to one. They are living documents that evolve and change with the project. It’s completely inappropriate to defend an inefficient practice with a style guide. It’s normal and healthy for them to evolve.

One last salient point of note is that a style guide provides guidelines which are not to be confused with mandates. Imposing Draconian constraints accomplishes nothing. It is perfectly acceptable to deviate provided there is good reason.

Index

Spacing and Brace Placement

All spacing and brace placement should conform to the default google style of clang-format. Using the defaults makes configuration easy and tenable to a wide range of audiences.

Use the following command to create a clang-format settings file

clang-format -style=google -dump-config > .clang-format

The easiest thing to do is configure clang-format in your IDE of choice (the Hideous Humpback Freak prefers Vim). However, if you wish to format via a CLI, use the following commands.

clang-format -i *.c
clang-format -i *.h

Columns

No line should exceed 80 columns wide

Non-Compliant

static void this_is_a_really_long_function_name_with_args(unsigned int param1, unsigned int param2) {
    ...
}

Compliant

static void this_is_a_really_long_function_name_with_args(unsigned int param1,
    unsigned int param2) {
    ...
}

Disadvantages

  • Loss of space when using large tab widths. (This is a non-issue for this project because the default tab-width for clang-format is 4)
  • Requires line breaks in unnatural locations in some extreme circumstances. (This is an accepted downside.)

Advantages

  • Easily display c, h, and test files side by side on a reasonable monitor
  • Snippets are easier to include in external documents
  • Default setting of clang-format

Include Guards

Use the #pragma once preprocessor directive to generate include guards.

Non-Compliant

#ifndef FILENAME_H
#define FILENAME_H
... file content
#endif /* !FILENAME_H */

Compliant

# pragma once

... file content

Disadvantages

  • #pragma once is non-standard; therefore, some compilers may not support it. Additionally, it could change. (This is of little concern because clang is the only supported compiler for this project.)

Advantages

  • Less code
  • Avoids naming collisions
  • Improves compilation speed

Include Directives

Include directives should be arranged with system include directives at the top, project level include directives in the middle, and local include directives at the bottom. Each section should be separated by a blank line.

Non-Compliant

#include "include/ResultCode.h"
#include <stdio.h>
#include "File.h"
... additonal includes

... file contents

Compliant

#include <stdio.h>
... additonal system includes

#include "include/ResultCode.h"
... additonal project includes

#include "File.h"
... additonal local includes

... file contents

Disadvantages

  • Requires developer discipline as this is not enforced by any linter

Advantages

  • Readability

Under Construction below this line

Function

  • Return values
    • clean up all allocation on error code
  • All internal are static
  • static beings with _

Every function should return a Result code indicating it’s status

typedef enum Result {
    NotFound = -8,
    Empty = -7,
    DependancyError = -6,
    ArgumentOutOfRange = -5,
    InvalidIndex = -4,
    ArithmeticOverflow = -3,
    FailedMemoryAllocation = -2,
    NullParameter = -1,
    Success = 0
} Result;

Result someFunction();

Any additional output should be returned via an output parameter, that should be placed as the last function parameter.

Result someFunction(const int par1, const float par2, struct *returnValue);