Code Style Standard¶
Comments¶
- All code shall be commented sufficiently that its operation and motivation would be clear to a reader who is familiar with the language and with Scout but has not read other project code or otherwise communicated with the coder
- Comments should not provide information that would be obvious to a competent engineer reading the associated code
- However, different engineers may have different values of obvious (or different values of competent :), so use your discretion
- Bad:
// Loop until there is no more data to read in while (read(file) != EOF)
- Good:
while (read(file) != EOF)
- Comments should provide any information otherwise absent that would be necessary or helpful for a competent engineer to understand the code
- Comments should document major design decisions made while writing the code
- If you fix a particularly subtle bug, a comment contradicting the false assumption that caused the bug might be appropriate
- Use your discretion
- Comments should minimally describe the purpose of a particular piece of code and its inputs and outputs
- Publicly (outside the file) visible unctions should be preceded by a Doxygen (
/**
) block comment describing purpose, usage, parameters, side effects, and return value- Here is a Doxygen tutorial to get you started
- This may be appropriate for other globally visible objects as well
- TODO: which ones?
File Naming¶
- Filenames shall effectively hint as to file content and have a dot-delimited extension that reflects file type
- Bad:
New File 5
- Good:
motors.c
- Bad:
- Filenames shall be composed entirely of lower-case English letters, digits, periods, and underscores
Function Naming¶
- Function names should be meaningful and unambiguous
- Use under_scores (no camelCase)
- i.e. usb_puts, motors_init
- First letter should be lowercase
- First "word" should describe the actor, following words describe the action
- i.e. use motors_init instead of init_motors
- multi-word examples: bom_get_max, range_read_distance
Variable Naming¶
- Variable names shall be meaningful and unambiguous
- e.g.
a
,var1
, andnumber
are probably bad variable names;motor_direction
is an OK variable name - Seemingly bad variable names are allowed where significant precedent makes their meaning clear
- e.g.
i
and subsequent one-letter variables for loop indexes
- e.g.
- e.g.
- Two variables in the same scope shall not vary only in capitalization or the use of underscores
- If two variables in different scopes have identical purposes, it may speed reader comprehension if they have the same name
- e.g. a function parameter and the argument passed to the function in that position
Macro Naming¶
- Names should be meaningful and unambiguous
- All caps with underscores between words
Use of Whitespace¶
- Braces beginning and ending blocks go on their own line, with the same indentation as the enclosing block
- Each nested block of code shall be indented from its containing block by 4 spaces (actual space characters)
- No tab characters shall appear in the source code
- No lines exceeding 80 printing characters in length
- Long lines that must be broken to comply with this rule shall be broken in such a way that each individual sub-line means as much by itself as possible
- Bad:
uint32_t function_name(uint32_t parameter1, uint32_t parameter2, uint32_t too_many_parameters);
Reader must remember parameter type across line break - Better:
uint32_t function_name(uint32_t parameter1, uint32_t parameter2, uint32_t parameter3);
Reader need only remember that they are reading the parameters to a function - In other words, break between tokens with the least nested syntactic relationship practical
- Bad:
- When breaking long lines, use a hanging indent of two normal indents (8 spaces)
- Bad:
if (/* overly long condition expression requiring a line break */) do_this();
Second line lines up with opening parenthesis, but is it part of the condition or the body? - Better:
if (/* overly long condition expression requiring a line break */) do_this();
Second line is clearly part of condition expression, notif
body
- Bad:
- Long lines that must be broken to comply with this rule shall be broken in such a way that each individual sub-line means as much by itself as possible
- Statements with parenthesized operands like
if
,while
, andfor
shall have exactly one space between the statement and the opening parenthesis - Conversely, function-call-like statements (function calls, function-like macro usage, compiler operators like sizeof()) shall have no space between the function name and the opening parenthesis
- This dichotomy helps visually differentiate constructs whose syntax is similar but whose semantics are not
- Lines shall not have extra whitespace after the last non-whitespace character (excluding the terminating newline character, obviously)
- Most binary operators should have a space between themselves and their operands
- Exceptions are when the combination of the two operands by the operator is more naturally thought about than the sequence of the three tokens
- Bad:
a=b+c/d+e.f->g
- A little better:
a = b + c / d + e . f -> g
- A lot better:
a = b + c / d + e.f->g
- There shall be no space between a parenthesis and the statement it encloses
- Obnoxious:
if ( function( a, b, c ) == d )
- Less so:
if (function(a, b, c) == d)
- Obnoxious:
- There shall be one space between opening comment delimiters (
//
or/*
) and the beginning of the comment - The indentation of comments shall match that of the surrounding code
- That is, comments shall be indented as if they were lines of code
- See examples for finer details of readable comments
- Bad:
//This is a comment /*So is this multi-line comment*/
- Better:
// This is a comment /* So is this multi-line comment */
- Two consecutive empty lines should never appear
- Files should end with a single newline
Parentheses and Other Grouping Operators¶
- Avoid unnecessary use of parentheses, as mentally determining grouping frustrates reader comprehension
- If you can't remember the order of operations, look it up. You will remember it better later, and your code will be better and cleaner for it.
- Exceptions in some cases where historical precedent or regularity suggest the use of parentheses, like
sizeof(variable)
Data Types and Macro Usage¶
- Use C99 data types as opposed to traditional data types to increase clarity and prevent arithmetic bugs
- Use
size_t
for array indexes- TODO: Appropriate use of the other special types dealing with pointers and the like is also desirable, but I confess that I cannot remember what they all are or what they are for
- Global variables accessed only from within their containing C file should be declared
static
- Variables not intended to be written to should be declared
const
- Compile-type constants should be specified using object-like macros (
#define
)- If you find yourself defining several constants that go together, use an enumerated type instead, e.g.
#define SUN 0 #define MON 1 #define TUE 2 #define WED 3 #define THU 4 #define FRI 5 #define SAT 6
becomestypedef enum { Sunday = 0, Monday = 1, Tuesday = 2, Wednesday = 3, Thursday = 4, Friday = 5, Saturday = 6 } weekdays;
- If you find yourself defining several constants that go together, use an enumerated type instead, e.g.
- Function-like macros (especially complicated or multi-step ones) should be avoided unless a worthy goal cannot be accomplished without them
- Use functions declared
inline
instead, or better yet, tell the compiler to automatically inline small functions and don't worry about it
- Use functions declared
- http://www.roboticsclub.org/redmine/wiki/colony/AVR_data_types is instructive