This standard is developed based on the general coding standards in the industry and is provided for developers for reference.
General Principles
- Clarity: easy to maintain and refactor
- Conciseness: easy to understand and implement
- Consistent code style
- Universality: compiling with the general coding standards in the industry
Directory Structure
You are advised to divide the project directories by referring to the LiteOS functional module division, and then define the header file directory and source file directory in the directories.
Naming Conventions
- CamelCase is the practice of writing compound words or phrases so that each word or abbreviation in the phrase begins with a capital letter, with no intervening spaces or punctuation.
| Type | Naming Style | Format |
| --------------------------- | -------------------------------- | ------------------------- |
| Functions and customized types | UpperCamelCase with or without a module prefix | AaaBbb, XXX_AaaBbb |
| Local variables, function parameters, macro parameters, structure members, and union members | lowerCamelCase | aaaBbb |
| Global variables | lowerCamelCase with the prefix 'g_' | g_aaaBbb |
| Macros, enumerated values | All-capitalized words separated by underscores (\_) | AAA_BBB |
| Macro variables that prevent duplicate kernel header files | All-capitalized module name with the prefix '_LOS' and suffix 'H', separated by underscores (\_) | \_LOS_MODULE_H |
- Names of global functions, global variables, macros, types, and enumerations shall be accurate and globally unique.
- Names of local variables or structure or union member variables should be as short as possible on the premise that related meanings can be accurately expressed.
- External LiteOS APIs are in the LOS_\\ format. For example:
```
LOS_TaskCreate
LOS_SwtmrStart
LOS_SemPend
```
APIs between internal modules in the kernel directory are in the Os\\ format. For example:
```
OsTaskScan
OsSwtmrStart
```
Low-level APIs provided by the arch directory for upper-layer modules are in the Arch\\ format.
In other cases, \\ can be used.
Typesetting and Formatting
- A program block is indented with spaces instead of tabs ('\t'). Four spaces are used for each indentation level.
- The K&R alignment style is used for braces. That is, the left brace of a function starts a new line and exclusively occupies the line. The other left braces follow statements and are placed in the end of a line.
The right brace starts a new line and nothing else is placed on the line, unless it is followed by the remaining part of the same statement, for example, else or else if or semicolon in the if statement. For example:
```c
struct MyType { // The left brace is placed at the end of the statement, with a space left between them.
...
}; // The right brace is followed by a semicolon (;).
```
```c
int Foo(int a)
{ // The left brace of the function starts a new line and exclusively occupies the line.
if (a > 0) { // The left brace is placed at the end of the statement, with a space left between them.
...
} else { // The right brace, "else", and subsequent left brace are in the same line.
...
} // The right brace exclusively occupies the line.
...
}
```
- Braces are used in conditional or loop statements. For example:
```c
if (objectIsNotExist) { // Braces are added to a single-line conditional statement.
return CreateNewObject();
}
```
```c
while (condition) {} // Braces are used even if the loop body is empty.
```
```c
while (condition) {
continue; // Braces are used even if the continue indicates the empty logic.
}
```
- The case or default statement is indented by one level in a switch statement. For example:
```c
switch (var) {
case 0: // The statement is indented by one level.
DoSomething1(); // The statement is indented by two levels.
break;
case 1:
DoSomething2();
break;
default:
break;
}
```
- Only one statement is written in a line.
- It is recommended that a statement contain a maximum of 120 characters. If the statement cannot be shortened, it must be written in multiple lines.
- When a line breaks, an operator is left at the end of the original line, and the new line is aligned by type or indented by one level. For example:
```c
// Assume that the first line exceeds the length limit.
if (currentValue > MIN && // After the line break, the Boolean operator is placed at the end of the line.
currentValue < MAX) { // The new line is aligned with the two operands of the (&&) operator.
DoSomething();
...
}
```
```c
// Assume that the line for function calling exceeds the length limit.
ReturnType result = FunctionName(paramName1,
paramName2,
paramName3); // Parameters are aligned with the preceding parameters.
```
```c
ReturnType result = VeryVeryVeryLongFunctionName( // The first parameter is too long, resulting in a line break.
paramName1, paramName2, paramName3); // The line is indented with four spaces.
```
```c
// If parameters represent a group of data structures with a strong correlation, they are placed in one line for ease of understanding. In this case, the understandability takes precedence over the formatting and typesetting requirements.
int result = DealWithStructLikeParams(left.x, left.y, // A group of related parameters.
right.x, right.y); // Another group of related parameters.
```
- When a function is declared or defined, the return type and other modifiers of the function are in the same line as the function name.
- The pointer type "\*" should follow the variable or function name on its right-hand side. For example:
```c
int *p1; // Good example: The pointer type "*" follows a variable on its right-hand side, and leaves a space between itself and the type on its left-hand side.
int* p2; // Bad example: The pointer type "*" follows the type on its left-hand side.
int*p3; // Bad example: The pointer type "*" leaves spaces on neither sides.
int * p4; // Bad example: The pointer type "*" leaves spaces on both sides.
```
If there are other modifiers between the pointer type "\*" and the variable or function name, the pointer type "\*" does not follow the modifiers. For example:
```c
char * const VERSION = "V100"; // Good example: When the const modifier exists, the pointer type "*" leaves spaces on both sides.
int Foo(const char * restrict p); // Good example: When the restrict modifier exists, the pointer type "*" leaves spaces on both sides.
```
- Blank lines are properly arranged based on the context relevance. Do not use three or more consecutive blank lines.
- The number sign (#) that starts a preprocessor directive is placed at the beginning of a line. The line does not need to be indented unless it is for a nested preprocessor directive. For example:
```c
#if defined(__x86_64__) && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16) // The number sign (#) is at the beginning of the line which is not indented.
#define ATOMIC_X86_HAS_CMPXCHG16B 1 // The line is indented by one level to facilitate reading.
#else
#define ATOMIC_X86_HAS_CMPXCHG16B 0
#endif
```
### Comments
- Comments must be clear, accurate, and non-ambiguous.
- Comments are used to express the function and intention of code, rather than repeating the code.
- Comments in the function declaration describe the function, performance, and usage, including the input and output parameters, return values, and reentering requirements. Comments in the function definition detail the function and implementation points, such as the procedure, reason, and design constraints.
- Detailed comments must be provided for global variables, including the function, value range, and access precautions.
- Abbreviations should be avoided in comments unless they are commonly used in the industry or are standardized in subsystems.
- Comments must be added to the file header. It is recommended that the comments contain the following information: copyright description, version number, generation date, author name, function description, relationship with other files, and modification log.
- The comment style must be unified. The /* */ format is recommended. There must be a space between the comment character and the content. The comment styles of a single line and multiple lines are as follows:
```c
/* Single-line comment */
```
```c
/*
* Multi-line comment
* Second line
*/
```
- Comments should be placed above or to the right of the code.
There is no blank line between the comment line and the code line. Indentations of the two lines are the same.
There must be at least one space between the code and the comment on the right. It is more appealing sometimes when multiple comments placed on the right are aligned vertically. For example:
```c
#define A_CONST 100 // The two comment lines are of the same type.
#define ANOTHER_CONST 200 // The lines are left-aligned.
```
### Macros
- The #ifdef macro is used to isolate code snippets. For example:
```c
#ifdef LOSCFG_XXX
...
#endif
```
- When defining a macro, use complete parentheses. For example:
```c
#define SUM(a, b) a + b // Unqualified.
#define SUM(a, b) ((a) + (b)) // Qualified.
```
However, the abuse of parentheses should be avoided. For example, it is meaningless to add parentheses to a single number or identifier.
```c
#define SOME_CONST 100 // Parentheses are not required for a single number.
#define ANOTHER_CONST (-1) // Parentheses are required for negative numbers.
#define THE_CONST SOME_CONST // Parentheses are not required for a single identifier.
```
- The function-like macro implementation statements that contain multiple statements must be placed in do-while(0). For example:
```c
#define FOO(x) do { \
(void)printf("arg is %d\n", (x)); \
DoSomething((x)); \
} while (0)
```
- Preprocessor directives are not allowed in arguments in macro calling.
- The macro definition does not end with a semicolon (;).
Header File
- Design principles
- The responsibility of a header file should be simple.
- It is recommended that all .c files in a module be stored in one directory whose name is the module name. If a module contains multiple sub-modules, it is recommended that each sub-module provide an external .h file whose name is the sub-module name.
- It is recommended that each .c file have a .h file with the same name, which is used to declare the APIs that need to be exposed externally.
- The header file is suitable for placing API declarations instead of implementations.
- Variables cannot be defined in the header file.
- Cyclic dependency of header files is forbidden. Cyclic dependency means that a.h contains b.h, b.h contains c.h, and c.h contains a.h.
- Header files should be self-contained. That is, any header file can be compiled independently. In addition, unnecessary header files should not be included.
- Header files must have #define guards to prevent multiple inclusions. For example, the following macro definition guards are used in the kernel:
```c
#ifndef _LOS__H // For example, _LOS_TASK_H
#define _LOS__H
...
#endif
```
- External function APIs or variables cannot be referenced in declaration. APIs provided by other modules or files can be used only by including header files.
- Header files cannot be included in extern "C".
- Header files are included in a reasonable sequence:
1\) Header file corresponding to the source file
2\) C standard library
3\) Other OS header files to be included
- Copyright Statement
- The copyright statements of header files are the same and placed on the top of each header file.
- If the submitted code is compiled or derived based on the open-source software, comply with the open-source license agreement and fulfill the license obligations of the modified software.
Data Types
Use types defined in los_typedef.h to define basic types. For example, use UINT32 to define an unsigned 32-bit integer variable.
### Variables
- Use a variable for only one purpose.
- Local and global variables must have different names.
- Do not use global variables if possible.
- When defining local variables of a function, limit the space occupied by variables to prevent program running failures due to excessive stack space occupation. For example, if a large array is required, you can dynamically allocate the memory to avoid occupying too much stack space.
- Initialize variables before using them for the first time.
- After a resource is released, a new value is immediately assigned to a variable that points to a resource handle or descriptor. The variables include the pointer, socket descriptor, file descriptor, and other variables that point to the resource.
- The address of a local variable cannot be returned outside its scope. The following is a **bad example:**
```c
int *Func(void)
{
int localVar = 0;
...
return &localVar; // Bad example
}
void Caller(void)
{
int *p = Func();
...
int x = *p; // The program generates undefined behavior.
}
```
**Good example:**
```c
int Func(void)
{
int localVar = 0;
...
return localVar;
}
void Caller(void)
{
int x = Func();
...
}
```
- If you want to use the variables of other modules, do not directly access the variables. Instead, use the unified function encapsulation or macro encapsulation mode. For example, in the mutex module:
```c
// Introduce global variables in the private header file. Do not use them directly.
extern LosMuxCB *g_allMux;
// Access g_allMux in GET_MUX mode.
#define GET_MUX(muxID) (((LosMuxCB *)g_allMux) + GET_MUX_INDEX(muxID))
```
### Functions
- Duplicate code should be extracted into functions as much as possible.
- Avoid long functions and ensure that each function contains no more than 50 lines.
- Inline functions must be as short as possible and cannot exceed 10 lines (non-null and non-comment).
- Avoid deep code block nesting.
- Do not use global variables, static local variables, or I/O operations in functions. If necessary, use them in a centralized manner.
### Portability
Do not use statements that are closely related to hardware or operating systems. Instead, use recommended standard statements to improve software portability and reusability.
Coding Standards in the Industry
There are many references to the C coding standards. You can learn them by yourself.
Document Writing Specifications
Huawei LiteOS \(hereinafter referred to as "LiteOS"\) welcomes developers to contribute to the open-source community. If contributors want to commit document changes or new documents, please refer to the following specifications.
### Naming
To commit a new document, create the .md file under the **doc** directory of the LiteOS code on Gitee. The file name must be in the **xxx_xxx.md** format.
For example, a document that describes writing specifications can be named **LiteOS\_doc\_write\_standard.md**.
### Content
The content should be concise and intuitive. Introductory documents describe principles, architecture, and design ideas in a concise manner, and operation documents describe key steps to help other developers. Chinese is preferred. It is recommended that both Chinese and English be supported. LiteOS will be updated continuously to ensure the synchronization between Chinese and English.
1. **Title**
It is recommended that the title have no more than three levels.
2. **Body**
- Operation documents: Porting is used as an example to show the document structure.
1. Purpose \(Briefly describe the purpose of the operation, for example, the model of the board to which the port is to be migrated.\)
2. Hardware and software requirements
3. Detailed steps
4. Result verification
- Introductory documents: A feature in a development guide is used as an example to show the document structure.
1. Overview \(concepts and principles\)
2. Functions \(supported APIs\)
3. Development process \(steps of how to use and develop\)
4. Programming examples \(sample code\)
5. Precautions
6. Others
3. **Images**
Images are stored in the **figures-en** folder in the directory where the document is stored. For example, images used in **LiteOS/doc/quick\_start/LiteOS\_doc\_write\_standard.md** are stored in **LiteOS/doc/quick\_start/figures-en**, and relative paths are used to reference images in the document. It is recommended that images be named based on the content. Using only a number is difficult for image inheritance.
> **NOTE:**
>Reference:
>!\[\]\(./figures/figures-standard.png\)
If a self-made image is used, refer to the following figure to configure the color. The format can be .png, .jpg, .gif, and so on. If a screenshot or an image referenced in other places is used, there is no restriction on the style.

4. **Table**
You can insert a table in the .md file in the following format:
```
| Tables | Type | Note |
| ----------- |:-------------:| -----:|
| first | standard | None |
| second | outstanding | 5 |
| third | inside | with |
```
5. **Code**
To insert a code segment in the body, add **\`\`\`** before and after the code segment. The following uses the C language as an example:
```c
int size = 10;
\```
Commit message Rules
There are multiple commit message rules. LiteOS uses the Angular specification, which is the most widely used format. It is reasonable and systematic, and has matching tools.
Function of Commit Messages
A formatted commit message has the following advantages:
- More historical information is provided for quick browsing.
- Certain commits (for example, document changes) can be filtered for easier search.
- Change logs can be directly generated from the commit operation.
Format of LiteOS Commit Messages
Each commit message contains three parts: header, body, and footer.
```
Blank line
Blank line