This page defines code style guidelines for my projects, but you are welcome to follow them in your projects as well :)
The rules here are loosely based on both the Linux kernel coding style as well as GNU Coding Standards, with tweaks based on my personal preferences (for both my sanity and readability, some GNU rules are actually insane).
Most of these rules can be applied to all programming languages, although the main target is modern C and C++.
i32 *ptr = NULL;
i32 *ref = &ptr;
const to #define when possible.int8_t, int16_t, int32_t, int64_t and their respective unsigned variants.switch block (or many if statements) can be longer, however for non-trivial functions try to keep them under 60 lines in length (excl. braces and comments)i32
fancy_function(...)
{
...
}
do this instead:
i32 fancy_function(...)
{
...
}
i32 fancy_function(i32 some_int, std::vector<std::vector<std::string>> long_vector,
f64 floating_point, std::vector<std::string> another_vector)
Make sure the parameters are aligned, use tabs first, then spaces to refine the alignment.
static.std::expected<T, E>.#include directives should appear at the very top of the source file in this order: standard headers, external library headers, internal project headers.#include <print>
#include <vector>
#include <string>
#include <curses.h>
#include <sqlite3.h>
#include "util/typedefs.hpp"
#include "util/file.hpp"
Note the empty lines between #include directives, this is mainly to differentiate what is standard, third-party and internal.
typedefs common integer and floating-point types (a different name in each project for whatever reason).#include <cstdint>
using u8 = std::uint8_t;
using u16 = std::uint16_t;
using u32 = std::uint32_t;
using u64 = std::uint64_t;
using i8 = std::int8_t;
using i16 = std::int16_t;
using i32 = std::int32_t;
using i64 = std::int64_t;
using f32 = float;
using f64 = double;
The same header in C would use typedef instead of using. Also for simplicity sake I have omitted the include guards. You can use it (and if committing to my repositories where I already use it you should), saving a couple keystrokes never hurt anyone.
#pragma once
#ifndef HEADER_H
#define HEADER_H
... definitions go here
#endif // HEADER_H
Or you could combine both if you feel like it:
#pragma once
#ifndef HEADER_H
#define HEADER_H
... definitions go here
#endif // HEADER_H
#include.stderr, in C++ you would use:
std::print(stderr, ...);
and in C you would instead use:
fprintf(stderr, ...)
--version) as well as the help flag (both short: -h, long: --help). If any of them is encountered, the normal execution of the program should be stopped.--version flag output using the BSD-3-Clause license:
[program name] [version] Copyright (c) [year] [creator] License: BSD-3-Clause <https://opensource.org/license/bsd-3-clause> This is free software: you are free to use, modify, and redistribute it under the terms of the BSD-3-Clause License. There is NO WARRANTY, to the extent permitted by law.Example of the
-h/--help flag output:
Usage: [executable name] [OPTIONS] [INPUT]...
Arguments:
[INPUT]... Path(s) to the file or directory
Options:
-h, --help Print this help text
--version Print version and copyright text
Source code is available at: <[repository link]>
Options themselves are prepended with 2 spaces, and the description is aligned to a single column.
The executable name should ideally be taken from argv[0].
std::array<std::string> fancy_string_array = {
...
};
std::array<i32> simple_int_array = {1, 2, 3};
In every other case it should look like this:
if (...)
{
do_stuff();
}
else
{
do_other_stuff();
}
i32 fancy_function()
{
return 0;
}
The GNU Coding Standards will try to make you believe that every single brace should be prepended by 2 spaces, supposedly to notice where the function (or conditional) body starts or ends, but this rule was written with GNU Emacs in mind (their formatter expects this). They will try to make you believe in many things, but some are downright insane and only make sense in already estabilished codebases (like GNU itself), where changing the style is not viable.
if, else, for statement(s). Therefore this is okay:
if (...)
do_stuff();
else
do_other_stuff();
for (i32 i = 0; i < 5; i++)
fancy_stuff();
However when only one branch has a single line, then use braces for both:
if (...)
{
do_a_thing();
do_other_thing();
}
else
{
do_single_thing();
}
// for short comments, as well as when closing an #ifdef/#ifndef block or a namespace (specifically when it's long, but do it every time just to be consistent).#ifdef CONDITION
...
#endif // CONDITION
namespace file
{
...
} // namespace file
/* ... */ for multi-line (longer) comments.static do not need to be documented) with their brief purpose (but keep it really brief), parameter list and a return value.Makefile to build the project.clang, however since the flags are mostly compatible with gcc, you can use it as well (but remember to change it in the Makefile)."do stuff" commit messages.