The following guidelines are conducive to clear and readable code that is consistent with the style of the rest of the Bonsai Computer System. 0. Use: - a single line for control flow statements short enough to be easily understood at a glance: if !(argc < 0) { usage(program_name); } This applies to C switch cases, as well. switch (value) { /* aligning stuff to make it easier to read is fine */ case possibility: variable = foo; break; default: variable = NULL; break; } - as little nested logic as possible (within reason). - braces in control flow, when their inclusion is left optional by a programming language (in, for example, C). if (condition) { statement; } - empty lines between different kinds of statements: int t; assert(io->bufuse > 0); assert(io->bufuse <= io->bs); if ((t = write(io->fd, io->buf, io->bufuse)) < 0) { io->error = errno; t = 0; } else if (t > 0) { memmove(io->buf, &(io->buf)[t], (io->bufuse -= t)); } io->bytes += t; io->prec += (t > 0 && io->bufuse > 0); io->rec += (t > 0 && io->bufuse == 0); return io; - compiler options that yield the most useful warnings, such as -Wpedantic in a lot of C compilers. Fix the warnings, too. See [0]. - fixed bounds for loops; see [0]. - one more level of indentation and one line per argument, when a function call or statement header is too long to fit on one line: let usage = format!( "Usage: {} [-d delimiter] index command [args...]", argv[0], ); - one more level of indentation than the keyword that initiated a block. if (condition) { statement; statement; } - the return value of all non-void functions, or explicitly ignore them (like casting to void in C): if ((a = malloc(sizeof char)) == NULL) { /* handle this error */ (void)fprintf(stderr, "oh noes!"); /* explicitly ignore this one */ return EX_OSERR; /* ...because the program is exiting anyway */ } See [0]. - the smallest possible scope for data; see [0]. - (C) comments noting all the symbols and macros used from a header, next to its include macro: #include /* close(2), getopt(3), lseek(2), read(2), write(2), (space-aligned) * optarg, optind, STDIN_FILENO, STDOUT_FILENO */ - (C) one more level of indentation within switch cases. switch (value) { case possibility: statement; default: statement; } - (C) spaces in control flow statements, after the keyword and before the opening brace: for (i = 2; i < argc; ++i) { - (Cpp) as little of the preprocessor as possible; see [0]. - (Rust) a trailing comma on all arguments or fields that are on their own lines: return Err(EvaluationError { message: format!("{}: Invalid token", i), code: EX_DATAERR, }) - (Rust) extern statements after use statements that include standard library crates. Group like statements: use std::fs::Path; extern crate strerror; extern crate sysexits; use strerror::StrError; use sysexits::{ EX_OSERR, EX_USAGE }; - (Rust) if text is on the same line as a brace, spaces after an opening curly brace and before a closing one: use sysexits::{ EX_DATAERR, EX_IOERR, EX_UNAVAILABLE, EX_USAGE }; - (Rust) one more level of indentation within match arms. 1. Avoid: - function pointers; see [0]. - heap memory allocation; see [0]. - too many levels of dereferences; see [0]. /* do not do this */ for (size_t i = 0; i < sizeof a / sizeof *a; ++i) { if (a[i].id == MATCH) { a[i].val = 0; } } /* do this */ for (struct MadeUp *s = &a[0]; *s != NULL; s = &s[1]) { if (s->id == MATCH) { s->val = 0; } } 2. Do not use: - more than the length of one printed page for a function; see [0]. - recursion, as it's complex and can unexpectedly overflow the stack; see [0] and section 2 of this document. - (C) any language features not in C99. - (C) do-while loops, as they're unique to the language and confusing for casual C programmers. - (C) gotos; use sensible flow control, see [0]. - (C) pointer arithmetic, as it tends to be confusing and unnecessary; use index-reference patterns like &p[1] instead of p + 1. &p[n] is the address at p + sizeof p * n, not p + n, like pointer arithmetic suggests. - (C) struct bitfields in unions, to access certain bits of bigger data types, as it's poorly defined in the C standards; use bit arithmetic. - (C) trigraphs. - (Cpp) inclusions in C header files, to prevent multiple file inclusions. - (Cpp) variables to prevent multiple inclusions of the same file, such as: #ifdef _FILE #define _FILE /* file body */ #endif /* ifdef _FILE */ Instead, take the time to ensure other files aren't including the any files twice. - (libc) any functionality not in the latest POSIX or C99. - (libc) gets(3p) from , as it's impossible to prevent buffer overflows when it's used; use fgets(3p) from . - (libc) scanf(3p) from ; see [1]. - (Make) any functionality not described in make(1p) from the latest POSIX. 2. Keep the following in mind: - Everyone knows that debugging is twice as hard as writing a program in the first place. So if you're as clever as you can be when you write it, how will you ever debug it? -- Brian Kernighan, in The Elements of Programming Style References ========== [0] [1] -- Copyright © 2024 Emma Tebibyte Copyright © 2024 DTB Copyright © Wikipedia contributors This work is licensed under CC BY-SA 4.0. To view a copy of this license, visit .