Tabs and Spacing

Two spaces (four is fine as well, just be consistent).

Why? Never use tabs unless strictly necessary (inside a Makefile, etc.). Tabs are inconsistent and more often than not make a mess of things online when people browse code in repositories like Github. This is the most common way people browse our code, and spaces ensure that the code is consistent and readable in any context.

Save your tabs for CircuitPython.

Naming Conventions

Learning from many of my own mistakes, these are the habits I've picked up over the years.

File Names

Use all lower case letters!

Why? While upper and lower case is a non-issue on Windows, it can cause endless headaches in other operating systems and build environments. Using only lower-case letters in your file names avoids this problem entirely, and your compiler will never complain that it can't find a file.

Function Names/Prototypes

Start with the filename, then append the function name
error_t pcf2129Init         ( void );
void    pcf2129SetCallback  ( void (*pFunc)(void) );
error_t pcf2129ReadTime     ( rtcTime_t *p_time );
error_t pcf2129SetTime      ( rtcTime_t time );
error_t pcf2129SetInterrupt ( pcf2129_INTEvent_t eventFlags );
Why? This just makes it easier to know exactly where a function is located when it's used somewhere. You might call hundreds of functions in a single file or complex chunk of code, and it isn't always easy to track them down by memory. Appending every function with the filename or something similar (sensor name, etc.) makes things much less ambiguous.

Field/Variable Names

Flag shared fields with '_' or 'm_' and use meaningful names
static bool _pcf2129Initialised = false;
static void (*_pcf2129Callback)(void) = NULL;
Why? It's helpful to have a clear visual queue of what's defined on a module level (fields or variables share by all functions in the file/module) and what's local and only exists on the stack.

You should also include the filename (or an abbreviation of it) in any global variables that you define like this to avoid problems debugging later when everything is linked together.
Flag pointer parameters with a 'p' or 'p_' prefix

To make sure that people understand that they are working with pointers and 'references' to external memory blocks, prefix all pointer parameters with either 'p' or 'p_':
error_t pcf2129ReadTime     ( rtcTime_t *p_time );
Why? Pointers allow for more efficient use of limited memory resources, but require special considerations in the code. By prefixing all pointers with a clear value, you set off an alarm bell in people's head to make sure that they understand they aren't working with a normal variable located on the local stack, etc.

Indent Style

Use whichever you prefer between Allman and K&R, just be consistent!

This is highly personal, but I've always been an Allman person, where the opening brace is on a newline:
/* Allman Style */
for ( i = 0; i < length; i++ )
  buffer[i] = I2CSlaveBuffer[i];
Many people seem to prefer K&R (where the opening brace is on the same line as the code), but I've always found this harder to follow.
/* K&R Style */
for ( i = 0; i < length; i++ ) {
  buffer[i] = I2CSlaveBuffer[i];
Why? I just find nested loops easier to read in Allman, but this is a personal choice and the important thing is being consistent.

This guide was first published on May 01, 2014. It was last updated on Apr 23, 2024.

This page (Basic Guidelines) was last updated on Apr 23, 2024.

Text editor powered by tinymce.