Despite being a single developer, I haven't always been the most consistent with my code style. I'm writing this document to standardize myself on a standard set of conventions.
- Data structures should be named
smb_followed by a two to four character abbreviation of their name/purpose. Examples include:smb_ll- Linked list.smb_iter- Iterator.
- Data structures should be declared as
typedef struct [name] { .... } [name];so that they may be referenced with or without thestructkeyword. - Data structure member variables should be lower case,
underscores_between_words, and should not have any abbreviation indicating their data structure.
- Functions should be named with
underscores_between_words. - Functions that deal with a module or data structure should be prefixed with the two to four character abbreviation for that data structure or module.
- Functions that do not deal with a data structure, but instead are library
level functions, should be prefixed with
smb_. - Private functions (those local to a code file, and without a declaration in a
header) need not be prefixed with anything, but should still follow the
underscores_between_wordsconvention.
- Local variables should also be named with
underscores_between_words. - Global variables should not be used enough to merit a specific style.
- Constants and macros should be in
ALL_CAPS_UNDERSCORES_BETWEEN_WORDS. - They should also generally be prefixed by
SMB_.
- All header files should go within the
libstephen/directory. - Library level declarations go within
libstephen/base.h. - Module level declarations should go within a file named after the module/data structure's abbreviation.
- Source files should generally be named after the module that they define. However, they may use an expanded version of the module's name so as to be clearer.
- Binary and ternary operators should be surrounded by spaces, except when compressing them lends readability to code.
- Comparison operators should be surrounded by spaces.
- Assignment operators should be surrounded by spaces.
- Unary operators (
-,++,--,*,&) should be attached to their operand. This applies to the pointer operators too. In declarations, the*should be attached to the variable being declared. - The dereferencing operator
->and field access operator.should not be surrounded by spaces.
- For function blocks, braces should start and end on a new line, and be the only characters on those lines.
- For control flow structures, the opening brace should be on the same line as the initial keyword, and the closing brace should be on its own line.
- When braces are on their own line, they should be at the indentation level of the containing block, not the block they define.
- Parentheses, in all cases, should not be separated from the text they enclose.
- In function calls, the opening parenthesis should not be separated from the function name.
- Every block should be indented two spaces from the containing block.
- Documentation comments should have an indentation level of three spaces from their containing block.
- Both
//and/* ... */comments are allowed. However,//should be preferred for most line comments that span one or two lines. - Larger, multiline comments can use
/* ... */, but you should consider whether that comment shouldgo within a documentation comment instead of a regular old comment. - Every function (public or private) should have a documentation comment
/*** ... */before it. It should use the Doxygen format with@as the keyword character. It should at least define a@brieffor a one line explanation of the function's purpose, and in most cases should document all parameters, return values, and errors, and provide an explanation sufficient for an API user. - Public functions are required to have the above.
- Files should start with a standard header (as can be seen in
src/linkedlist.c). It should contain@file,@author,@date, and@brief. After the@brief, a more full explanation of the module may be provided, if necessary. - Comments may be used to delimit sections of code. They should be of the form forward slash, 79 asterisks, blank line, centered header title line, blank line, 79 asterisks, and forward slash.
- System headers should be included first, followed by a blank line, followed by libstephen headers.
- Error handling should be a high priority, but it should not overtake the
entire code -- especially with code to handle rare and difficult to handle
memory allocation errors. So, errors thrown by
mallocwill be dealt with bysmb_new()by printing to stderr and terminating. Any call tosmb_new()can be assumed to be successful without error checking. There will be no memory allocation error handling. - Error handling should always be achieved by a
statusparameter to a function. The status parameter should be the last parameter in the function, and it should have typesmb_status*. smb_statusshould be an integer, defining status codes as constants:SMB_SUCCESSSMB_INDEX_ERRORSMB_NULL_ERROR- etc
- The status variable should be checked after every function call. No
exceptions.
- If an error condition is impossible, then that should be documented with an assertion.
gotos are permissable for handling errors in code which needs to free resources.
- Assertions from
assert.hshould be used throughout code. As with all assertions, they should only be used to indicate a bug in the program. That is, assert things that could only happen if there was a bug in the program. An assertion should never fire due to something like out of bounds input (unless it is an internal function where all input has already been checked).