Style Guide

Style guide should be followed for all C/C++ code developed for WARG. Generally, we want to follow the guide set by BAARS C or MISRA C, although generally our style follows that of the google c++ guide. Google C++ Style Guide. A .clang-format will be uploaded soon.

[ 1 File Naming ] [ 1.1 Zeropilot ] [ 1.2 Laminar OS ] [ 2 Formatting ] [ 2.1 Spacing ] [ 2.2 Variables ] [ 2.2.1 Static variables ] [ 2.2.2 Constants ] [ 2.2.3 Pointers ] [ 2.2.4 Declaring Variables on the Same Line ] [ 2.2.5 Structs and Classes ] [ 2.3 Mathematics ] [ 2.3.1 Mathematical Operations ] [ 2.4 Selection ] [ 2.4.1 Conditions ] [ 2.4.1.1 Operations ] [ 2.4.1.2 Order of Terms ] [ 2.4.2 If Statements ] [ 2.4.2.1 Structure ] [ 2.4.3 Ternary Expressions ] [ 2.4.4 Switch Statements ] [ 2.5 Loops ] [ 2.5.1 Curly Brackets ] [ 2.5.2 Breaks ] [ 2.6 Functions ] [ 2.6.1 Naming and Brackets ] [ 2.6.2 Parameters ] [ 2.6.2.1 Parameter names ] [ 2.6.2.2 Pointers ] [ 2.6.2.3 Reference Parameters ] [ 2.6.2.4 More than one Parameter ] [ 2.6.3 Commenting ] [ 2.7 Data Structures ] [ 2.7.1 Classes ] [ 2.7.1.1 Member Variables: follow variable naming ] [ 2.7.1.2 Constructors ] [ 2.7.1.3 Initializing Classes ] [ 2.7.2 Structs ] [ 2.7.2.1 Initializing Structs ] [ 2.7.3 Enums ] [ 2.7.4 Further reading ]

File Naming

With the introduction of ZP and LOS, there’s an increased pressure to name well. Please refer to the ZP / LOS architecture spec for directory structure.

Zeropilot

Zeropilot file names should be prefixed by their corresponding category, and then be in Pascal Case. I.E:

AM_Interface.cpp // Attitude Manager Interface SF_MahonyFilter.hpp // Sensor Fusion Mahony Filter

There should be very few exceptions to this rule. Try to make names descriptive and follow our design pattern.

Laminar OS

LaminarOS is a bit more difficult. For interface layers, the name of the file should be prefixed only by LOS_:

LOS_Link.cpp // RC-Link interface LOS_Pos.cpp // LOS Position interface LOS_Telem.hpp // LOS Telemetry interface

LOS Core and LOS Driver layers should be prefixed by LOS_C_ and LOS_D_ respectively. Los CORE generally will have names of protocols, please follow the naming conventions for those protocols, otherwise use all uppercase. Drivers should be in all lowercase (since a lot of these will also be names like PPM or CRSF, but using all caps makes it easier to confuse with core)

LOS_C_I2C.Xpp LOS_C_GPIO.Xpp LOS_C_UART.Xpp LOS_C_TIM.Xpp LOS_D_imu.Xpp LOS_D_ppm.Xpp LOS_D_xbees.Xpp

Formatting

Spacing

We use 4 spaces instead of tabs here.

Hard line limit of 80 characters.

Variables

Note: For class and struct member conventions, refer to the Data Structures section.

Generally, variables should follow snake case.

As a rule of thumb, all variables should be initialized upon declaration to prevent undefined behaviour.

Static variables

Static variables should be appended with an underscore

Constants

Constants (const and constexpr) should be named using screaming case, never lead with an underscore

Pointers

The* should be attached to the variable:

As a rule of thumb, all pointers must be initialized on declaration. If you are not assigning it a value, then set it to nullptr like the example above.

Declaring Variables on the Same Line

Declaring and initializing multiple variables of the same type can be done on the same line. However, the number of variables on the line should not exceed 5:

Structs and Classes

When declaring structs, classes, or any object for that matter, we will prefer to use C++'s implementation of value initialization so all parameters are default initialized (are given their default value).

Mathematics

Mathematical Operations

There should always be spaces around all mathematical operators. There should always be spaces between equal signs.

Selection

Conditions

Operations

There must be a space around all operations (==, >=, &&, etc.)

Additionally, if a condition list has more than one condition, any condition containing mathematical operations must be surrounded in brackets:

Order of Terms

When comparing the value of a variable, it is best practice to put the value before the variable identifier. This prevents runtime errors from occuring in case you use = instead of ==.

If Statements

Structure

There must be a space around the if and else keywords, and there must be a space separating the condition list and the opening curlly-bracket. Curly-brackets must be on the same line as the condition list.

Always use curly brackets, even if the code within the if statement is one line.

Ternary Expressions

Pretty standard.

Switch Statements

Switch statements are pretty standard too, just need to get the indentation right. Also, ensure you put breaks in every condition unless you cannot put it:

Loops

Curly Brackets

Should be on the same line as the do, for, and while keyword:

Also keep a space between the do, for, and while keyword; conditions, and open curly-bracket.

Conditions follow same rules as if statements.

Breaks

We try to avoid using the break keyword when exiting loops. Instead, use a boolean flag to track if the loop is done executing.

continue statements will be allowed, however they should only be used if it will simplify the code by a significant amount.

Functions

Naming and Brackets

Functions should use lower camel case in their names. There should be no spaces between the function name and the parameter list. The open curly-bracket must be on the same line as the function name, and must be separated from the parameter list by one space:

Parameters

Parameter names

Parameter names should follow the same conventions as written in the Variables section.

Pointers

The* in pointers must be separated on both sides by one space.

NOTE: Moving forward, we will prefer to use reference parameters over pointers when passing by reference. It is a more C++ style of programming.

Reference Parameters

The & in reference parameters must be appended to the datatype of the parameter.

We will prefer to use this C++ feature when passing values by reference. To learn more about reference parameters, you can refer to the following links:

More than one Parameter

Parameters in a list must be separated by commas (obviously lol), but a space must separate a comma and a parameter:

If the parameter list is very long, creating a vertical list of parameters is acceptable too. Just ensure each parameter starts in the same column so as to ensure readability.

Commenting

All function declarations must have a comment above describing its purpose, parameters, and returned value. Pay notice to the spacing on the* and the /** that opens the comment

Data Structures

Classes

Classes use PascalCase. Public member variables and methods will be declared first, followed by protected and then private:

Member Variables: follow variable naming

Constructors

We prefer to use initializer lists when initializing member variables, however there are cases where we should stick to initializing member variables within the constructor.

Initializing Classes

When statically declaring a struct, you should initialize it immediately. If a default constructor exists, call that, else call another constructor.

If declaring a class pointer, initialize to nullptr if no other options exist:

Structs

Structs should only be used to store Plain Old Data (POD). That means no methods should ever be declared in a struct. If you need method, use a class :))

Structs will use PascalCase for their names. We will use the following syntax:

If you are making a typedef, append a _t.

Initializing Structs

When statically declaring a struct variable, always initialize upon declaration:

When declaring a struct variable pointer, initialize it to nullptr if no other options exist:

Enums

We use PascalCase for enunms, and the constants will use all caps with underscores separating words. Additionally, the first constant should have a = 0 appended to it.

Further reading

https://barrgroup.com/sites/default/files/barr_c_coding_standard_2018.pdf