These rules are meant as guidelines for writing C++ for FIRST Team 422. These are not hard-and-fast rules; code should first and foremost be designed in a logical manner. However, these guidelines allow consistency and readability to be maintained across all of the robot's code. Do not break them without good reason.
This document is modeled after the [Google Code C++ style guide] (http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml).
Every header file must be wrapped in a #define
guard. These guards ought
to be named after the file they represent, e.g. a file named
"articulated_arm.hpp" should have a #define
guard like this:
#ifndef ARTICULATED_ARM_HPP
#define ARTICULATED_ARM_HPP
//Body of function
#endif //ARTICULATED_ARM_HPP
Trailing comments, like the one in the example above, are recommended.
Statements beginning with using namespace
should never be used in header
files, as they pollute the global namespace. Instead, names should be referenced
by their full name, e.g. std::vector
.
Avoid using global variables and functions. Use methods and member variables of classes when possible.
Declare local variables at the top of their enclosing scope, that is, at the top of the block in which they are declared. Initialize variables on declaration, like this:
int i = 0;
Rather than this:
int i;
i = 0;
If variables are used only once, for readability, make them const
and keep them directly above the line that they are used in.
When assigning values to member variables in a constructor, use the initialization list rather than the body of the constructor when possible. That is, do this:
Foo::Foo() :
bar(0),
baz(1) {
//Initialize
}
Rather than this:
Foo::Foo() {
bar = 0;
baz = 1;
//Initialize
}
This method is both more efficient and the only valid method to initialize constant member variables, so using it consistently helps prevent errors.
Default constructors must be defined for all classes.
Structs should be used only for containers for data, they must not have methods. When in doubt, use a class.
Class members should be declared as private
unless absolutely
necessary. Getters and setters should be used for changing member variables of
classes, rather than making the variables public. Getters and setters should be
named get_variable_name()
and set_variable_name( variable_type new_variable_name )
respectively.
public
class members should be declared before private
class members, and
variables should be declared before methods, e.g.
class Foo {
public:
int i;
bar();
private:
int j;
baz();
}
Functions should be as short as possible. Functions ought to accomplish one and
only one task, and be descriptively named to fit that task, e.g. raiseArm()
.
Do not use exceptions, as they make control flow difficult to understand and require extremely safe coding to avoid memory leaks.
Use C++ style casting, i.e. static_cast<int>(i)
, rather than C-style casting,
i.e. (int)i
.
Use the prefix form of ++
and --
whenever either form would be acceptable,
e.g. ++i;
rather than i++;
Use only int
, not long
, short
, or unsigned
. If other integer types are
needed, use the consistent types from <stdint.h>
, such as int_32_t
or
uint_64_t
.
Avoid using preprocessor macros when possible.
Use 0 for integers and pointers, 0.0 for reals, and '\0' for chars.
Constants should be declared as const type name = value;
, rather than using
#define
. This prevents unexpected behavior, for example when subtracting
negative constants.
Use descriptive names, avoid abbreviations.
File names should be in lower_case.
Type names are in Title_Case. This applies to classes, structs, enums, and all other user-defined types.
Variable names are in lower_case. Additionally, boolean variables should imply
their type by beginning with "is" or "are", such as is_robot_moving
.
Constants should be named in UPPER_CASE.
Functions should be in lower_case, and usually should contain a verb in their
name, e.g. move_forward()
not just forward()
.
Enums should be named in Title_Case; enum values should be named in UPPER_CASE.
Macros should be named in UPPER_CASE.
Comments within the body of a method, function, and/or class should avoid using
the multi-line form. Instead, multiple-line comments should simply have //
at
the beginning of each line.
Implementational comments, that is, describing how code works, should be written
as normal comments. Descriptive comments, i.e. describing what code is meant to
achieve, should be Doxygen comments. Doxygen comments within methods, functions,
and/or classes should use the ///
or ///<
forms, comments outside of these
may use the multi line /** ... */
form.
Additional documentation on Doxygen may be found here.
Incomplete or poorly-implemented sections of code should be marked with a
ccomment formatted as //TODO: An explanation of the problem
. If documentation
is incomplete, instead use /// @todo An explanation of what's missing
.
Every line should be no more than 80 characters long.
Tabs should be used for logical indentation, and spaces for alignment. This prevents alignment from being distorted by different tab sizes.
Curly braces should open on the same line as the expression that requires a new block. For example:
int foo() {
//function body
}
Rather than:
int foo()
{
//function body
}
A closing curly brace should be alone on its line, do not, for example, open an else statement on the same line as the end of an if statement, i.e.
if(condition) {
//do something
} else {
//do something
}
Instead prefer:
if(condition) {
//do something
}
else {
//do something
}
Conditional statements must always use curly braces, even when they only span one line.
Boolean expressions spanning more than one line should have the joining operator
(either ||
or &&
) at the beginning of each line, not the end.
Parentheses should indicate order of operations in all expressions containing
more than one operator, even when technically unnecessary, e.g. 1 + ( 1 * 2 )
.
Parentheses used for grouping should have a space before and after their contents.
Access specifiers (public
, private
, and protected
) should not be indented
with the body of the class.