The purpose of this article is to describe the coding standing used in the IoT-Developer-Boot-Camp project. The coding standard is necessary to maintain consistency throughout the project implementation to provide a professional support to all of the users. Furthermore, adopt the coding standard increases productivity and simplifies the projects maintenance since there are lots of contributor in this project.
-
- Use spaces, not tabs (Required)
- Indents are 2 spaces per level (Required)
- Lines should not be longer than 80 characters (Recommended)
- Use only plain ASCII or UTF-8 (Required)
- Use ISO8601 formatting for dates (Required)
- Inserting empty and blank lines (Required)
- Use parentheses liberally (Required)
- Break up long expressions (Required)
-
Functions, operators and C keywords
- Listing function parameters (Required)
- Using function parentheses (Required)
- Binary and ternary operators (Required)
- Use a single space after C keywords (Required)
- Additional space within expressions
- Identify do-nothing code (Recommended)
- Pointer asterisk position (Required)
- Don't mix pointer and value type declarations (Required)
We can't put everything into these guidelines, for things not covered in the guidelines, try to make your code blend in with the surrounding code you are editing. Use your best judgment!
All of the pull request to merge into the master branch need to be reviewed and approved by any people in the reviewer list below, and the developers should make sure that all of the new source code implemented following the coding standard.
Reviewers: Mark.ding Jim.Lin Eric.Su Cheng.Yuan
The coding standard guide details how your code should look, e.g. brace style, comment style etc. Some of the coding standard are marked as Required and others are Recommended. The Recommended rules should generally be followed expect some special circumstances, and the Required rules should always be followed.
For indenting files, use spaces and never tabs. A mix of tabs and spaces is never acceptable.
Indent each nested level with 2 spaces of indent.
We enforce an 80 characters limit per line of source code. This lets people set up their editors such that they can have multiple editors side-by-side. Although 80 characters are little by modern standards, it mixes well with existing code.
Text files should almost always contain only plain ASCII. Specifically, avoid characters outside the usual whitespace and printable ones (0x9-0xD and 0x20-0x7E, inclusive). Internationalized strings, when used, are best placed in a resource file. In the rare case that other characters are needed in a text file and cannot be escaped, the file should be UTF-8 encoded with no byte-order mark.
If you use a date in the comments or elsewhere, specify it using the unambiguous ISO8601 format, i.e. 2019-10-10.
There should never be consecutive blank rows. Use two slashes (C++ comment) and 77 dashes to separate logical parts of the code. Use 2 slashes and 32 dashes for minor sections. Use of section separators as shown here is optional. Example
// -----------------------------------------------------------------------------
// Here we start a new logical part in this source/header file...
// -------------------------------
// And here comes a new minor section...
Add parentheses if you have any doubt at all about precedence, not doing so has led to some very obscure bugs. This is especially true of the bitwise binary operators {&, |, ^} and Boolean operators {&&, ||}.
Whenever there are long expressions, it should be broken into multiple lines. When a line is broken into multiple lines, each line should start with the operator that operates on that full line (single element or a group of elements within parentheses). The operator must be the first thing on the line, and it should be indented appropriately. Example
int bitmask = (OPTION_1
| OPTION_2
| (IS_THIS_SET
? OPTION_3
: OPTION_4));
int bitmask = (OPTION_1
| OPTION_2
| (IS_THIS_SET ? OPTION_3 : OPTION_4));
int bitmask = (OPTION_1
| OPTION_2
| (OPTION_3 & OPTION_4));
Comment: All the above are examples of nicely formatted long expressions. Below is an example how you should not format long and complex expressions.
// Avoid this...
int no-good-formatting = (OPTION_1
| OPTION_2
| OPTION_3 & OPTION_4);
All inline code comments should use the C++ style //. However there are two exceptions to this rule. First, function and file documentation blocks use a different style (see documentation section below). Second, for multi-line macros using #define, C style comments /* ... */ should be used for embedded comments (see example below). For both kinds of comments, there should be a space following the opening comment marker. For example // My comment. Make sure constant values in the code are explained. Function calls with raw constants should be labeled based on the parameter that is being passed in. Example
// Example for the exception
// This type is needed because using // would swallow the line continuation marker.
#define MY_CLI_COMMANDS \
/* This command takes 3 arguments: */ \
/* Node ID - a 2-byte node ID destination */ \
/* Endpoint - a 1-byte node ID */ \
/* Cluster - a 2-byte cluster ID */ \
{ "my_command", myCommandFunction, "vuv" },
// Example of how to comment constant values.
// For the function declaration below
void function(int seconds, boolean printOutput);
// we add comments after each parameter (OPTIONAL)
function(0, // seconds
FALSE); // printOutput
Use the so called "One True Brace Style" Indent increases one level after an opening brace, and decreases one level before a closing brace. Opening braces do not go on their own separate line, except for free standing blocks and function definitions. Closing braces are on their own separate line with nothing else on these lines. All if/else blocks must be enclosed by braces, even if there is only one statement in the conditional. Exceptions for the above rule are; 1. The typedef alias for a composite (struct/union) or enum type is on the same line as the closing brace. 2. In a do-while loop the condition ( while (...); ) is on the same line as the closing brace. 3. else and else if are on the same line as the closing brace. Example
void foo(uint8_t bar)
{
if (foo > bar) { // The preceding brace is *required*
doThis();
} else {
doAnotherThing();
}
if (foo > bar) {
doThis();
}
do {
doWork();
} while (foo);
}
typedef enum {
SPADE,
HEART,
CLUB,
DIAMOND
} CardSuit_t;
The cases in switch statements should be indented one level from the enclosing braces. Separate case blocks with a blank line after each break;. All switch statements should include a default block unless there is a good reason not to. The default block can collapse into one of the other cases but it should clearly show what happens when there is no matching case. Finally, if a case block does not end with an unconditional jump, there should be a comment clearly stating that the code is intentionally meant to fall through. Example
switch(baz) {
case 1:
doThis();
break;
case 2:
doThat();
// This case is meant to fall through to the next
case 3: {
doTheOtherThing();
break;
}
case 0:
default:
doWhat();
break;
}
Whenever there is a list of function parameters, they should all fit on a single line or be listed one parameter per line. If listed on separate lines, each parameter has the same indent level as the first parameter. Example
void myFunction(int a,
int b,
int c,
const char *string1,
const char *string2)
{
// ...
}
void myFunction2(int a, int b, int c)
{
// ...
}
For function declarations, definitions and calls, there shall be no spaces before or after the opening parentheses, or before the closing parentheses. Example
int foo(int days, int seconds);
// ...
ret = foo(days, seconds);
Use spaces around binary & ternary operators in expressions. C expressions are hard enough to parse without running them altogether. Example
for (j = 0; j < parameterSizes[i]; j++) {
C keywords (ex. for, switch, while, if, do) – should have a single space after the keyword. Example
while (counter < UART_MAX_IO_BUFFER) {
Use of additional whitespace within expressions to improve readability is permitted as long as it doesn't interfere with appropriate multi-line expression indentation. Such style should be consistent within the module.
Avoid loops that do not make it obvious that they do nothing. Add a comment to explain the reason for the do-nothing loop. This applies to any code that does not do anything. Example
// Don't do:
while (waiting_for_something);
// Instead do:
// Useful comment explaining why you are waiting
while (waiting_for_something);
When declaring a pointer to a variable, the pointer asterisk should be placed together with the variable name, not together with the type. Example
// Don't do:
char* c = (char*)a;
void foo(uint32_t* bar);
// Instead do:
char *c = (char *)a;
void foo(uint32_t *bar);
Don't mix declarations of pointer type variables and value type variables on the same line. Example
// Don't do:
uint32_t *a, b;
// Instead do:
uint32_t *a;
uint32_t b;
Special care should be taken when creating new functions. The name should convey the purpose of the function as clearly as possible.
Function names should be in camelCase with the first letter lowercase. Example
void radioTrasmit();
When a verb and a noun the verb acts on are in a function name, the verb should come first (getPower, not powerGet). It should feel natural to read the name. Variables and functions of boolean type should use a naming style indicating the sense of the boolean. For example isConnected. Example
// This is for legacy EM code and does not apply to 8051
// code base.
getPower(); // Call to a new-style API function.
// Below is an example of how to redefine old style API calls to the new syntax.
#if (SLAB_OLD_API == SLAB_REPLACE_OLD_API_CALLS)
#define powerGet getPower
#define powerSet setPower
#endif
All constants should be named and use upper case letters. Avoid raw numbers in code.
To separate words in a constant use underscore ('_') between words (see example). Example
#define SLAB_WEDNESDAY 4
All types use CamelCase with the first letter uppercase.
Each typedef must end with a '_t' suffix and cannot start with 'int', 'uint' or 'unicode'.
If the type is a typedef, you can optionally add a type name if there is a reason the anonymous type does not work. In this case use the same name as the typedef name, without the '_t'. Example
// Anonymous structure name ...
// Use this style in most cases.
typedef struct
{
// ...
} NvmPageHeader_t;
// You can use this style if the struct needs a name.
typedef struct NvmPageHeader
{
// ...
} NvmPageHeader_t;
All file names are lower case and multiple words are separated with one underscore '_'. Example
packet_buffer.c
Avoid using the same file name for source files. Note: Among our entire source code there will be files with the same name. This cannot be avoided. But files with the same name should never be used in the same project/build.
Directories use lower case names and underscores as word separators.
Revision 1.0
- 2019-09-26
- Initial Revision