OpenHarmony-c-coding-style-guide.md 79.0 KB
Newer Older
W
wusongqing 已提交
1
# C Coding Style Guide
N
NEEN 已提交
2

3
## Purpose
N
NEEN 已提交
4

W
wusongqing 已提交
5
Rules are not perfect. They might disable useful features in specific situations and therefore affect code implementation. However, the purpose of developing rules is to get more benefits for most programmers. If a rule cannot be followed in your team operation, we can improve the rule together. Before referring to this coding style guide, you are expected to have the following basic capabilities of the C programming language:
N
NEEN 已提交
6 7 8 9 10

1. Understand the ISO standard of C.
2. Be familiar with the basic features of C.
3. Understand the standard library of C.

11
## General Principles
N
NEEN 已提交
12 13 14

Code must meet the requirements for **readability**, **maintainability**, **security**, **reliability**, **testability**, **efficiency**, and **portability** while ensuring functionality correctness.

15
## Conventions
N
NEEN 已提交
16

W
wusongqing 已提交
17 18
**Rule**: Conventions that must be followed during programming.

W
wusongqing 已提交
19
**Rec**: Conventions that must be considered during programming.
N
NEEN 已提交
20

W
wusongqing 已提交
21
It is necessary to understand the reason for these conventions and try to comply with them, no matter if they are rules or recommendations.
N
NEEN 已提交
22

23 24 25
## Exceptions

The only acceptable exceptions are those that do not violate the general principles and provide appropriate reasons for their existence.  
N
NEEN 已提交
26

W
wusongqing 已提交
27
Try to avoid exceptions because they affect the code consistency. Exceptions to 'Rules' should be very rare.
N
NEEN 已提交
28

29 30
The style consistency principle is preferred in the following case: 

W
wusongqing 已提交
31
**When you modify open-source or third-party code, comply with their respective code specifications.**
N
NEEN 已提交
32

33
# 1 Naming
N
NEEN 已提交
34 35 36

Names include file, function, variable, type, and macro names.

37 38
Naming is considered the most difficult and important thing in software development. 

W
wusongqing 已提交
39
The name of an identifier must be clear, well defined, easy to understand, and accounting for reading habits.
N
NEEN 已提交
40 41 42

The unified naming style is the most direct expression of the consistency principle.

43 44 45
## General Conventions

**CamelCase** 
N
NEEN 已提交
46

W
wusongqing 已提交
47
CamelCase is the practice of writing compound words or phrases so that each word or abbreviation in the phrase begins with a capital letter, and with no intervening spaces or punctuation.
48

W
wusongqing 已提交
49
There are two conventions: **UpperCamelCase and lowerCamelCase**.
N
NEEN 已提交
50

51 52
**Unix\_like** 

W
wusongqing 已提交
53
Unix\_like is also known as the snake style. In the Unix\_like style, words contain only lowercase letters and are separated by underscores (\_).
54

W
wusongqing 已提交
55 56
Example: 'test_result'

57
### Rule 1.1 Name identifiers in the CamelCase style.
N
NEEN 已提交
58

59 60 61 62 63 64 65
| Type| Naming Style|
|----------|----------|
| Function, struct, enum, union| UpperCamelCase|
| Variable, function parameter, macro parameter, struct body, union member| lowerCamelCase|
| Macro, constant, enumerated value, goto tag| All capitalized, separated by underscores (\_)|

Note: 
N
NEEN 已提交
66

W
wusongqing 已提交
67
**Constant** in the above table refers to the variable that is of the basic data type, enum type, and string type and modified by **const** under the global scope, excluding arrays, structs, and unions.
68

W
wusongqing 已提交
69
**Variable** indicates the variables excluding those defined in **Constant**. These variables use the lowerCamelCase style.
70

W
wusongqing 已提交
71
Unix\_like can be used for Linux or Unix friendly code.
72

W
wusongqing 已提交
73
For code that is using the Unix\_like style, you can continue using this style.
74

W
wusongqing 已提交
75
The same naming style must be used for the same function, struct, or union.
N
NEEN 已提交
76

77 78 79
### Rec 1.1 Use more accurate names for identifiers with a large scope.

Different from C++, C does not have namespace or class. Therefore, the names of identifiers in the global scope must not conflict with each other.  
N
NEEN 已提交
80

W
wusongqing 已提交
81
Names of global functions, global variables, macros, types, and enums must be accurately described and unique in the global scope.
N
NEEN 已提交
82 83 84 85

Example:

```c
W
wusongqing 已提交
86
int GetCount(void);                 // Bad: inaccurate description
N
NEEN 已提交
87 88 89
int GetActiveConnectCount(void);    // Good
```

W
wusongqing 已提交
90
For purposes of accurate naming, a module prefix can be added if necessary.
91 92 93

The module prefix and the naming body can be connected by following the CamelCase style.  

N
NEEN 已提交
94 95 96
Example:

```c
W
wusongqing 已提交
97
int PrefixFuncName(void);   // OK: CamelCase, a prefix in the content, but not in the format
N
NEEN 已提交
98

W
wusongqing 已提交
99
enum XxxMyEnum {            // OK
N
NEEN 已提交
100 101 102 103
    ...
};
```

104
## File Naming
N
NEEN 已提交
105

106
### Rec 1.2 Use lowercase file names.
N
NEEN 已提交
107

W
wusongqing 已提交
108
Only lowercase letters, numbers, and underscores (\_) are allowed in file names.
109 110 111

File names should be as short, accurate, and unambiguous as possible.  

W
wusongqing 已提交
112
The reason for using lowercase file names is that different systems process file names in different ways. (For example, file names in MS-DOS and Windows are not case sensitive, but those in Unix/Linux and macOS are case sensitive by default).
N
NEEN 已提交
113

114 115
Good example: 

N
NEEN 已提交
116 117 118
`dhcp_user_log.c`

Bad examples:   
119

W
wusongqing 已提交
120
`dhcp_user-log.c`: It is not recommended that you separate words with the hyphen (-).
N
NEEN 已提交
121 122
`dhcpuserlog.c`: The words are not separated, causing poor readability.

123
## Function Naming
N
NEEN 已提交
124

W
wusongqing 已提交
125
Functions are named in the UpperCamelCase style.
N
NEEN 已提交
126

127
### Rec 1.3 Name functions to comply with reading habits.
N
NEEN 已提交
128

W
wusongqing 已提交
129
The "verb + object" structure can be used for action related function names. Example:
N
NEEN 已提交
130 131 132 133 134 135 136

```c
AddTableEntry() // OK 
DeleteUser()    // OK
GetUserInfo()   // OK
```

W
wusongqing 已提交
137
An adjective or a prefix "is" can be used in a function returning a Boolean value. Example:
N
NEEN 已提交
138 139 140 141 142 143 144 145 146 147 148 149 150 151

```c
DataReady()     // OK
IsRunning()     // OK
JobDone()       // OK
```

Data or Getter function:

```c
TotalCount()    // OK
GetTotalCount() // OK
```

152
## Variable Naming
N
NEEN 已提交
153 154 155

Variables are named in the lowerCamelCase style. This includes global variables, local variables, parameters in the function declaration or definition as well as parameters in function-like macro.

156
### Rule 1.2 Add the 'g_' prefix to global variables, but not to static variables in a function.
N
NEEN 已提交
157

W
wusongqing 已提交
158
Global variables should be used as little as possible, and special attention should be paid to their use. This prefix highlights global variables so that developers can be more careful when handling them.
159

W
wusongqing 已提交
160
Global static variables and global variables are named in the same way. Static variables in functions and common local variables are named in the same way.
N
NEEN 已提交
161 162 163 164 165 166 167 168 169 170 171

```c
int g_activeConnectCount;

void Func(void)
{
    static int pktCount = 0;  
    ...
}
```

W
wusongqing 已提交
172
Notes: Constants are also global variables in essence. However, if constants are named using uppercase letters separated by underscores (\_), the current rule does not apply.
N
NEEN 已提交
173

174
### Rec 1.4 Keep local variables short and to the point.
N
NEEN 已提交
175 176 177

The name of a local variable should be short on the premise that meanings can be expressed through context.

W
wusongqing 已提交
178
Example:
N
NEEN 已提交
179 180 181 182

```c
int Func(...)
{
W
wusongqing 已提交
183
    enum PowerBoardStatus powerBoardStatusOfSlot; // Not good: Long redundant local variable
N
NEEN 已提交
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
    powerBoardStatusOfSlot = GetPowerBoardStatus(slot);
    if (powerBoardStatusOfSlot == POWER_OFF) {
        ...
    }    
    ...
}
```

Better writing style:

```c
int Func(...)
{ 
    enum PowerBoardStatus status;   // Good: The status can be clearly expressed in context.
    status = GetPowerBoardStatus(slot);
    if (status == POWER_OFF) {
        ...
    }
    ...
}
```

Similarly, "tmp" can be used to address any type of temporary variable.   
207

W
wusongqing 已提交
208
A short variable name should be used with caution, but sometimes a single-character variable is allowed, for example, a counter variable in a loop statement.
N
NEEN 已提交
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226

```c
int i; 
...
for (i = 0; i < COUNTER_RANGE; i++) {
    ...
}
```

Or, variables in simple math functions:

```c
int Mul(int a, int b)
{
	return a * b;
}
```

227
## Type Naming
N
NEEN 已提交
228

W
wusongqing 已提交
229 230
Types are named in the UpperCamelCase style.

W
wusongqing 已提交
231
The type can be a struct, a union, or an enum.
N
NEEN 已提交
232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247

Example:

```c
struct MsgHead {
    enum MsgType type;
    int msgLen;
    char *msgBuf;
};

union Packet {
    struct SendPacket send;
    struct RecvPacket recv;
};

enum BaseColor {
W
wusongqing 已提交
248
    RED,    // Note: The enum is in the UpperCamelCase style whereas the enumerated values adopt the macro naming style.
N
NEEN 已提交
249 250 251 252 253 254 255
    GREEN,
    BLUE
};

typedef int (*NodeCmpFunc)(struct Node *a, struct Node *b);
```

W
wusongqing 已提交
256
When you use `typedef` to set an alias for a struct, a union, or an enum, try to use the anonymous type.
N
NEEN 已提交
257 258 259 260 261 262
If you need self-nesting pointers, you can add a 'tag' prefix or an underscore suffix.

```c
typedef struct {    // Good: The anonymous struct is used because self-nesting is not required.
    int a;
    int b;
W
wusongqing 已提交
263
} MyType;           // The struct alias uses the UpperCamelCase style.
264 265
```
```c
N
NEEN 已提交
266 267 268 269 270 271
typedef struct tagNode {    // Good: Add the 'tag' prefix or use 'Node_'.
    struct tagNode *prev;
    struct tagNode *next;
} Node;             // UpperCamelCase.
```

272
## Macro, Constant, and Enum Naming
N
NEEN 已提交
273

W
wusongqing 已提交
274
Use uppercase letters separated by underscores (\_) for macro names and enumerated values.
275

W
wusongqing 已提交
276
You are advised to use uppercase letters separated with underscores (\_) for constant names. Global const variables can be named with the same style of global variables.
277

W
wusongqing 已提交
278
The constants here are defined as global const variables of the basic data type, enum type, or string type.
N
NEEN 已提交
279

W
wusongqing 已提交
280
Use uppercase letters separated by underscores (\_) for function-like macros.
281

W
wusongqing 已提交
282
Exceptions:
283

W
wusongqing 已提交
284 285 286 287
1. Functions that use macros to implement generic functions, for example, macros that implement functions such as list and map, can be named in the same way as functions, using the UpperCamelCase style.
2. A function-like macro that is used to replace a function in the earlier version can be named in the same way as functions, using the UpperCamelCase style.
3. Macros for printing logs can be named in the same way as functions, using the UpperCamelCase style.
Note: Function-like macros named in the UpperCamelCase style must be marked as macros in the API description.
N
NEEN 已提交
288 289 290 291 292 293 294 295 296 297 298

Macro example:

```c
#define PI 3.14
#define MAX(a, b)   (((a) < (b)) ? (b) : (a))
```

```c
#ifdef SOME_DEFINE
void Bar(int);
W
wusongqing 已提交
299
#define Foo(a) Bar(a)   // The function-like macro is named in the same way as a function.
N
NEEN 已提交
300 301 302 303 304 305 306 307 308 309
#else
void Foo(int);
#endif
```

Constant example:

```c
const int VERSION = 200;    // OK.

W
wusongqing 已提交
310
const enum Color DEFAULT_COLOR = BLUE; // OK
N
NEEN 已提交
311

W
wusongqing 已提交
312
const char PATH_SEP = '/';  // OK
N
NEEN 已提交
313

W
wusongqing 已提交
314
const char * const GREETINGS = "Hello, World!"; // OK
N
NEEN 已提交
315 316 317 318 319
```

Non-constant example:

```c
W
wusongqing 已提交
320
// A struct that does not meet the definition of constants
N
NEEN 已提交
321 322
const struct MyType g_myData = { ... };     // OK: Name it in lowerCamelCase style.

W
wusongqing 已提交
323
// An array that does not meet the definition of constants
N
NEEN 已提交
324 325 326 327
const int g_xxxBaseValue[4] = { 1, 2, 4, 8 };   // OK: Name it in lowerCamelCase style.

int Foo(...)
{
W
wusongqing 已提交
328
    // A local const variable that does not meet the definition of constants
N
NEEN 已提交
329 330 331 332 333
    const int bufSize = 100;    // OK: Name it in lowerCamelCase style.
    ...
}
```

W
wusongqing 已提交
334
Enum example:
N
NEEN 已提交
335 336

```c
W
wusongqing 已提交
337
// Note: The enum type name is in the UpperCamelCase style, whereas the enumerated value is in uppercase letters separated by underscores (\_).
N
NEEN 已提交
338 339 340 341 342 343 344
enum BaseColor {
    RED,
    GREEN,
    BLUE
};
```

345
### Rec 1.5 Avoid temporary variables in function-like macros from polluting external scopes.
N
NEEN 已提交
346

W
wusongqing 已提交
347
**If possible, use a function instead of a function-like macro. Define a function-like macro only when necessary.**
N
NEEN 已提交
348

W
wusongqing 已提交
349
When defining local variables for a function-like macro, use double underscores at the end to avoid name conflicts with local variables in external functions. Example:
N
NEEN 已提交
350 351
```c
#define SWAP_INT(a, b) do { \
W
wusongqing 已提交
352
    int tmp__ = a; \
N
NEEN 已提交
353
    a = b; \
W
wusongqing 已提交
354
    b = tmp__; \
N
NEEN 已提交
355 356 357
} while (0)
```

358
# 2 Formatting
N
NEEN 已提交
359

360
## Line Length
N
NEEN 已提交
361

362
### Rule 2.1 Include 120 characters or less in each line.
N
NEEN 已提交
363

W
wusongqing 已提交
364
A longer line makes it more difficult for reading.
365

W
wusongqing 已提交
366
To meet the line length requirement, you can shorten the names of functions and variables and reduce the number of nesting layers. This improves code readability.
367

W
wusongqing 已提交
368
Unless a long line is necessary to maintain readability and present complete information, steer your document clear of long lines.
369

W
wusongqing 已提交
370
Even on a high-resolution monitor, a long line increases the difficulty of reading. Strive for clearness and conciseness.
N
NEEN 已提交
371

W
wusongqing 已提交
372
Exceptions:
N
NEEN 已提交
373

W
wusongqing 已提交
374 375
- For code lines or comments, the use of the line feed causes content truncation and increases the search difficulty (grep).
- The #include and #error statements are allowed to exceed the line length requirement. However, you should try to avoid this.
N
NEEN 已提交
376 377 378 379 380 381 382 383 384

Example:

```c
#ifndef XXX_YYY_ZZZ
#error Header aaaa/bbbb/cccc/abc.h must only be included after xxxx/yyyy/zzzz/xyz.h
#endif
```

385
## Indentation
N
NEEN 已提交
386

387 388 389
### Rule 2.2 Use spaces to indent and indent four spaces at a time.

Only spaces can be used for indentation. Four spaces are indented each time. Do not use the Tab character to indent.  
N
NEEN 已提交
390

W
wusongqing 已提交
391
Currently, almost all integrated development environments (IDEs) and code editors support automatic conversion of a Tab input to fours spaces. Configure your code editor to support indentation with spaces.
N
NEEN 已提交
392

393 394 395 396 397
## Braces

### Rule 2.3 Use the K\&R indentation style.

**K\&R style** 
N
NEEN 已提交
398

399
While wrapping a line, the left brace of the function starts a new line and takes a single line. Other left braces are placed at the end of the line along with the statement.  
N
NEEN 已提交
400

W
wusongqing 已提交
401
The right brace takes a single line, unless it is followed by the rest of the same statement, such as `while` in the `do` statement, `else` or `else if` in the `if` statement, a comma, or a semicolon.
N
NEEN 已提交
402

W
wusongqing 已提交
403
Example:
N
NEEN 已提交
404 405

```c
W
wusongqing 已提交
406
struct MyType {     // Good: The left brace is placed at the end of the line along with the statement, and one space is used for indentation.
N
NEEN 已提交
407 408 409 410 411 412 413
    ...
};                  // Good: The right brace is followed by the semicolon.

int Foo(int a)
{                   // Good: The left brace of the function starts a new line, and nothing else is placed on the line.
    if (...) {
        ...
W
wusongqing 已提交
414
    } else {        // Good: The right brace is followed by the `else` statement.
N
NEEN 已提交
415 416 417 418 419
        ...
    }               // Good: The right brace takes a single line.
}
```

420
## Function Declaration and Definition
N
NEEN 已提交
421

422
### Rule 2.4 Keep the return type and function name of the function declaration or definition in the same line, and align the function parameter list appropriately if it needs to be wrapped.
N
NEEN 已提交
423 424 425 426 427 428

When a function is declared and defined, the return value type of the function should be in the same line as the function name.

When the function parameter list is wrapped, it should be aligned appropriately.   
The left parenthesis of a parameter list is always in the same line as the function name. The right parenthesis always follows the last parameter.

W
wusongqing 已提交
429
Example:
N
NEEN 已提交
430 431

```c
W
wusongqing 已提交
432
ReturnType FunctionName(ArgType paramName1, ArgType paramName2)   // Good: All in one line
N
NEEN 已提交
433 434 435 436
{
    ...
}

W
wusongqing 已提交
437 438
ReturnType VeryVeryVeryLongFunctionName(ArgType paramName1,     // Each added parameter starts on a new line because the line length limit is exceeded.
                                        ArgType paramName2,     // Good: Aligned with the previous line
N
NEEN 已提交
439 440 441 442 443
                                        ArgType paramName3)
{
    ...
}

W
wusongqing 已提交
444 445
ReturnType LongFunctionName(ArgType paramName1, ArgType paramName2, // Parameters are wrapped because the line length limit is exceeded.
    ArgType paramName3, ArgType paramName4, ArgType paramName5)     // Good: 4 spaces are used for indentation.
N
NEEN 已提交
446 447 448 449
{
    ...
}

W
wusongqing 已提交
450 451
ReturnType ReallyReallyReallyReallyLongFunctionName(            // The line length cannot accommodate even the first parameter, and a line break is required.
    ArgType paramName1, ArgType paramName2, ArgType paramName3) // Good: 4 spaces are used for indentation.
N
NEEN 已提交
452 453 454 455 456
{
    ...
}
```

457
## Function Calls
N
NEEN 已提交
458

459
### Rule 2.5 Align the parameter list appropriately if it needs to be wrapped.
N
NEEN 已提交
460

W
wusongqing 已提交
461
In a function call, if the function parameter list is wrapped, it should be aligned appropriately.
462

N
NEEN 已提交
463 464
The left parenthesis is always followed by a function name, and the right parenthesis always follows the last parameter.

W
wusongqing 已提交
465
Example:
N
NEEN 已提交
466 467

```c
W
wusongqing 已提交
468
ReturnType result = FunctionName(paramName1, paramName2);   // Good: Function parameters are placed in one line.
N
NEEN 已提交
469 470

ReturnType result = FunctionName(paramName1,
W
wusongqing 已提交
471
                                 paramName2,                // Good: Aligned with the above parameters
N
NEEN 已提交
472 473 474
                                 paramName3);

ReturnType result = FunctionName(paramName1, paramName2, 
W
wusongqing 已提交
475
    paramName3, paramName4, paramName5);                    // Good: 4 spaces are used for indentation.
N
NEEN 已提交
476

W
wusongqing 已提交
477 478
ReturnType result = VeryVeryVeryLongFunctionName(           // The line length cannot accommodate the first parameter, and therefore line feed is used.
    paramName1, paramName2, paramName3);                    // 4 spaces are used for indentation.
N
NEEN 已提交
479 480
```

W
wusongqing 已提交
481
If the parameters in a function call are associated with each other, you can group the parameters for better understanding, rather than strictly adhering to the formatting requirements.
N
NEEN 已提交
482 483

```c
W
wusongqing 已提交
484
// Good: The parameters in each line represent a group of data structures with a strong correlation.They are placed on one line for ease of understanding.
N
NEEN 已提交
485 486 487 488
int result = DealWithStructureLikeParams(left.x, left.y,     // Indicates a group of parameters.
                                         right.x, right.y);  // Indicates another group of related parameters.
```

489
## Conditional Statements
N
NEEN 已提交
490

491
### Rule 2.6 Use braces for conditional statements.
N
NEEN 已提交
492

W
wusongqing 已提交
493
Use braces to enclose conditional statements, even if there is only one statement.
494

N
NEEN 已提交
495 496 497 498 499 500 501 502 503 504 505 506
Reason:

- Logic is intuitive and easy to read.
- It is not easy to make mistakes when adding new code to the existing conditional statement.
- Function-like macros without braces are used in conditional statements, can be error prone if braces do not surround the conditional statement.

```c
if (objectIsNotExist) {         // Good: Braces are added to a single-line conditional statement.
    return CreateNewObject();
}
```

507
### Rule 2.7 Do not place `if`, `else`, and `else if` in the same line.
N
NEEN 已提交
508

W
wusongqing 已提交
509
In a conditional statement, branches, if any, should be written in different lines.
N
NEEN 已提交
510

W
wusongqing 已提交
511
Good example:
N
NEEN 已提交
512 513 514 515

```c
if (someConditions) {
    ...
W
wusongqing 已提交
516
} else {    // Good: The `else` statement is in a different line of `if`.
N
NEEN 已提交
517 518 519 520
    ...
}
```

W
wusongqing 已提交
521
Bad example:
N
NEEN 已提交
522 523 524 525 526

```c
if (someConditions) { ... } else { ... } // Bad: They are in the same line.
```

527
## Loops
N
NEEN 已提交
528

529
### Rule 2.8 Use braces for loop statements.
N
NEEN 已提交
530

W
wusongqing 已提交
531
Use braces to enclose the `for` and `while` statements, even if there is only one loop.
N
NEEN 已提交
532 533 534 535 536 537 538 539

```c
for (int i = 0; i < someRange; i++) {   // Good: Braces are used.
    DoSomething();
}
```

```c
W
wusongqing 已提交
540
while (condition) { }   // Good: The entire loop body is empty. And braces are used.
N
NEEN 已提交
541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556
```

```c
while (condition) { 
    continue;           // Good: The continue keyword highlights the end of the empty loop. And braces are used.
}
```

Bad example:

```c
for (int i = 0; i < someRange; i++)
    DoSomething();      // Bad: Braces should be added.
```

```c
W
wusongqing 已提交
557
while (condition);      // Bad: The semicolon may be treated as part of the `while` statement.
N
NEEN 已提交
558 559
```

560
## `switch` Statements
N
NEEN 已提交
561

562
### Rule 2.9 Indent the `case` or `default` statement in a `switch` statement block.
N
NEEN 已提交
563

W
wusongqing 已提交
564
Use the following indentation style for the `switch` statement:
N
NEEN 已提交
565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589

```c
switch (var) {
    case 0:             // Good: Indented
        DoSomething1(); // Good: Indented
        break;
    case 1: {           // Good: Braces are added.
        DoSomething2();
        break;
    }
    default:
        break;
}
```

```c
switch (var) {
case 0:                 // Bad: 'case' not indented
    DoSomething();
    break;
default:                // Bad: 'default' not indented
    break;
}
```

590
## Expressions
N
NEEN 已提交
591

592
### Rec 2.1 Keep a consistent line break style for expressions and ensure that operators are placed at the end of the line.
N
NEEN 已提交
593

W
wusongqing 已提交
594
A long expression that does not meet the line length requirement must be wrapped appropriately. Generally, the expression is wrapped after a lower-priority operator or a hyphen, and the operator or hyphen is placed at the end of the line, indicating that the operation is to be continued.
N
NEEN 已提交
595 596 597 598

Example:

```c
W
wusongqing 已提交
599 600
// Assume that the first line does not meet the line length requirement.
if ((currentValue > MIN) &&  // Good: The Boolean operator is placed at the end of the line.
N
NEEN 已提交
601 602 603 604 605 606 607 608 609
    (currentValue < MAX)) {    
    DoSomething();
    ...
}

int result = reallyReallyLongVariableName1 +    // Good: The plus sign is placed at the end of the line.
             reallyReallyLongVariableName2;
```

W
wusongqing 已提交
610
After an expression is wrapped, ensure that the lines are properly aligned or indented by 4 spaces. Example:
N
NEEN 已提交
611 612

```c
L
liuhui 已提交
613 614
int sum = longVariableName1 + longVariableName2 + longVariableName3 +
    longVariableName4 + longVariableName5 + longVariableName6;         // OK: indented with 4 spaces
N
NEEN 已提交
615

L
liuhui 已提交
616 617
int sum = longVariableName1 + longVariableName2 + longVariableName3 +
          longVariableName4 + longVariableName5 + longVariableName6;   // OK: aligned
N
NEEN 已提交
618 619
```

620
## Variable Assignment
N
NEEN 已提交
621

622
### Rule 2.10 Do not write multiple variable definitions or assignment statements in one line.
N
NEEN 已提交
623

W
wusongqing 已提交
624
It is recommended that each line contain only one variable initialization statement, which is easier to read and understand.
N
NEEN 已提交
625 626 627 628 629 630

```c
int maxCount = 10;
bool isCompleted = false;
```

W
wusongqing 已提交
631
Bad example:
N
NEEN 已提交
632 633

```c
W
wusongqing 已提交
634 635
int maxCount = 10; bool isCompleted = false; // Bad: Multiple initialization statements are placed in one line.
int x, y = 0;  // Bad: Multiple variable definitions are placed in one line.Each definition occupies one line.
N
NEEN 已提交
636 637 638 639

int pointX;
int pointY;
...
W
wusongqing 已提交
640
pointX = 1; pointY = 2;  // Bad: Multiple variable assignment statements are placed in one line.
N
NEEN 已提交
641 642
```

W
wusongqing 已提交
643 644
Exceptions:
If multiple variable definitions have strong correlation and do not need to be initialized, you can define the variables in a line for code compactness.
N
NEEN 已提交
645 646

```c
W
wusongqing 已提交
647
int i, j;  // Good: Multiple variable definitions that do not need to be initialized are written in one line.
N
NEEN 已提交
648 649 650 651 652 653 654
for (i = 0; i < row; i++) {
    for (j = 0; j < col; j++) {
        ...
    }
}
```

655
## Initialization
N
NEEN 已提交
656 657 658

Initialization is applicable to structs, unions, and arrays.

659
### Rule 2.11 Use indentation or make a reasonable alignment for a new line.
N
NEEN 已提交
660

W
wusongqing 已提交
661
For the struct or array initialization, use 4 spaces for indentation if a line break is made.
662

W
wusongqing 已提交
663
From better readability, make a reasonable alignment.
N
NEEN 已提交
664 665 666 667 668

```c
// Good: No line break for a short line.
int arr[4] = { 1, 2, 3, 4 };

W
wusongqing 已提交
669
// Good: A line break makes better readability.
N
NEEN 已提交
670 671 672 673 674 675 676 677 678 679 680
const int rank[] = { 
    16, 16, 16, 16, 32, 32, 32, 32,
    64, 64, 64, 64, 32, 32, 32, 32
};
```

For complex data, the initialization should be clear and compact.   
Refer to the following format:

```c
int a[][4] = {
W
wusongqing 已提交
681
    { 1, 2, 3, 4 }, { 2, 2, 3, 4 }, // OK
N
NEEN 已提交
682 683 684 685
    { 3, 2, 3, 4 }, { 4, 2, 3, 4 }
};

int b[][8] = {
W
wusongqing 已提交
686
    { 1, 2, 3, 4, 5, 6, 7, 8 },     // OK
N
NEEN 已提交
687 688 689 690 691 692 693
    { 2, 2, 3, 4, 5, 6, 7, 8 }
};
```

```c
int c[][8] = {
    {
W
wusongqing 已提交
694
        1, 2, 3, 4, 5, 6, 7, 8      // OK
N
NEEN 已提交
695 696 697 698 699 700 701 702
    }, {
        2, 2, 3, 4, 5, 6, 7, 8
    }
};
```

Note:

W
wusongqing 已提交
703
- If the left brace is placed at the end of the line, the corresponding right brace should be placed into a new line.
N
NEEN 已提交
704 705
- If the left brace is followed by the content, the corresponding right brace should also follow the content.

706
### Rule 2.12 Initialize each member in a separate line during struct and union member initialization.
N
NEEN 已提交
707

W
wusongqing 已提交
708
The C99 standard supports the initialization of the struct and union members in their definition. This is called the designated initializer. In such a way, each member should be initialized in a separate line.
N
NEEN 已提交
709 710 711 712 713 714 715 716

```c
struct Date {
    int year;
    int month;
    int day;
};

W
wusongqing 已提交
717
struct Date date = {    // Good: When the designated initializer is used, each member is initialized in a separate line.
N
NEEN 已提交
718 719 720 721 722 723
    .year   = 2000,
    .month  = 1,
    .day    = 1 
};
```

724
## Pointers
N
NEEN 已提交
725

726
### Rec 2.2 Ensure that the asterisk (\*) in the pointer type is followed by the variable name or follows the type. There must be a space before or after the asterisk.
N
NEEN 已提交
727

W
wusongqing 已提交
728
When you declare or define a pointer variable or return a pointer type function, the asterisk can be placed on the left (following the type) or right (followed by the variable name). There must be only one space before or after the asterisk.  
N
NEEN 已提交
729 730

```c
W
wusongqing 已提交
731 732
int *p1;    // OK
int* p2;    // OK
N
NEEN 已提交
733

W
wusongqing 已提交
734 735
int*p3;     // Bad: No space
int * p4;   // Bad: Space on both sides
N
NEEN 已提交
736 737 738 739
```

Choose a style and stay consistent.

W
wusongqing 已提交
740
If you use the asterisk to follow the type, do not declare multiple variables with pointers in a line.
N
NEEN 已提交
741 742

```c
W
wusongqing 已提交
743
int* a, b;  // Bad: b may be treated as a pointer.
N
NEEN 已提交
744 745
```

W
wusongqing 已提交
746 747
Do not use the asterisk followed by the variable name if this style is not suitable in all cases.
Keep style consistency first.
N
NEEN 已提交
748 749

```c
W
wusongqing 已提交
750 751
char * const VERSION = "V100";      // OK
int Foo(const char * restrict p);   // OK
N
NEEN 已提交
752 753
```

W
wusongqing 已提交
754
Do not use the asterisk to follow the `const` or `restrict` keywords.
N
NEEN 已提交
755

756
## Compilation Preprocessing
N
NEEN 已提交
757

758
### Rule 2.13 Place the number sign (#) at the beginning of a line for compilation preprocessing. In nested compilation preprocessing, the number sign (#) can be indented.
N
NEEN 已提交
759 760

The number sign (#) must be placed at the beginning of a line for compilation preprocessing, even if the code is embedded in the function body.
761

W
wusongqing 已提交
762
Try your best not to use compilation preprocessing macros. If they are needed in deed, they should be managed by dedicated personnel in a unified manner.
N
NEEN 已提交
763

764
## Whitespace
N
NEEN 已提交
765

766
### Rule 2.14 Use horizontal whitespaces to highlight keywords and important information, and avoid unnecessary whitespaces.
N
NEEN 已提交
767 768 769

Horizontal spaces should be used to highlight keywords and important information. Do not add spaces at the end of each line of code. The general rules are as follows:

W
wusongqing 已提交
770
- Add spaces after keywords such as `if`, `switch`, `case`, `do`, `while`, and `for`.
N
NEEN 已提交
771 772 773
- Do not add spaces after the left parenthesis or before the right parenthesis.
- Add a space before and after each binary operator (= + - \< > \* / % \| \& \^ \<= >= == !=).
- Do not add a space after any unary operator (\& \* + - ~!).
W
wusongqing 已提交
774
- Add a space before and after each ternary operator (? :).
N
NEEN 已提交
775
- Add spaces before and after the colon of bit field description.
W
wusongqing 已提交
776 777
- Do not add spaces between ++/-- and variables.
- Do not add spaces before and after the struct member operator (. ->).
N
NEEN 已提交
778
- Adding or not adding spaces inside the brace must be consistent.
W
wusongqing 已提交
779 780 781 782
- Do not add spaces before commas, semicolons, or colons (excluding the colon in the ternary operator or the bit field description). Add spaces after them.
- Do not add spaces between the parentheses of the function parameter list and the function name.
- Do not add spaces between the parenthesis of the type cast and the object being converted.
- Do not add spaces between the square bracket of the array and the array name.
N
NEEN 已提交
783 784
- Spaces at the end of the line can be omitted.

W
wusongqing 已提交
785
For spaces inside the braces, the following **recommendations** are available:
N
NEEN 已提交
786

W
wusongqing 已提交
787 788 789
- It is recommended that spaces be added after the left brace and before the right brace.
- For an empty constant or a constant with a single identifier or a single word, spaces are not required, for example, '{}', '{0}', '{NULL}', '{"hi"}'.
- Spaces between consecutively nested multiple parentheses are not required, for example, '{{0}}', '{{ 1, 2 }}'. '{ 0, {1}}' is a bad example, since it is not a consecutively nested scene and the spaces inside the outermost braces are inconsistent.
N
NEEN 已提交
790 791 792 793 794

In normal cases:

```c
int i = 0;                  // Good: When the variable is initialized, there should be spaces before and after the =. Do not leave a space before the semicolon.
W
wusongqing 已提交
795
int buf[BUF_SIZE] = {0};    // Good: For array initialization, spaces in curly braces are optional.
N
NEEN 已提交
796 797 798 799 800 801 802
int arr[] = { 10, 20 };     // Good: A space is added before and after the brace.
```

Function definition and call:

```c
int result = Foo(arg1,arg2); 
W
wusongqing 已提交
803
                      ^         // Bad: There is no space after the comma.
N
NEEN 已提交
804 805 806 807 808 809 810 811

int result = Foo( arg1, arg2 );
                 ^          ^   // Bad: No space should be added to either side in the parentheses.
```

Pointer and address-of operator:

```c
W
wusongqing 已提交
812 813
x = *p;     // Good: There is no space between the operator (*) and the pointer p.
p = &x;     // Good: There is no space between the operator (&) and the variable x.
N
NEEN 已提交
814
x = r.y;    // Good: When a member variable is accessed through the operator (.), no space is added.
W
wusongqing 已提交
815
x = r->y;   // Good: When a member variable is accessed through the operator (->), no space is added.
N
NEEN 已提交
816 817 818 819 820
```

Operator:

```c
W
wusongqing 已提交
821 822 823
x = 0;    // Good: There is a space before and after the assignment operator (=).
x = -5;   // Good: There is no space between the minus sign (-) and the number.
++++x; // Good: There is no space between ++/-- and the variable.
N
NEEN 已提交
824 825
x--;
    
W
wusongqing 已提交
826 827 828
if (x && !y)        // Good: There is a space before and after the Boolean operator, and there is no space between the operator (!) and variable.
v = w * x + y / z;  // Good: There is a space before and after binary operators.
v = w * (x + z);    // Good: There is no space before and after the expression in the parentheses.
N
NEEN 已提交
829 830 831 832 833
```

Loops and conditional statements:

```c
W
wusongqing 已提交
834
if (condition) {    // Good: A space is added between the `if` keyword and the parenthesis, and no space is added before or after the conditional statement inside the parentheses.
N
NEEN 已提交
835
    ...
W
wusongqing 已提交
836
} else {            // Good: A space is added between the `else` keyword and the curly brace.
N
NEEN 已提交
837 838 839
    ...
}

W
wusongqing 已提交
840
while (condition) {}    // Good: A space is added between the `while` keyword and the parenthesis, and no space is added before or after the conditional statement inside the parentheses.
N
NEEN 已提交
841

W
wusongqing 已提交
842
for (int i = 0; i < someRange; ++i) {  // Good: A space is added between the `for` keyword and the parenthesis, and after the semicolons (;).
N
NEEN 已提交
843 844 845
    ...
}

W
wusongqing 已提交
846 847
switch (var) {  // Good: A space is added after the `switch` keyword.
    case 0:     // Good: No space is added between the `case` conditional statement and the colon (:).
N
NEEN 已提交
848 849 850 851 852 853 854 855 856
        ...
        break;
    ...
    default:
        ...
        break;
}
```

W
wusongqing 已提交
857
Note: The current IDE and code editor can be set to delete spaces at the end of a line. Configure your editor correctly.
N
NEEN 已提交
858

859
### Rec 2.3 Arrange blank lines reasonably to keep the code compact.
N
NEEN 已提交
860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899

Reduce unnecessary blank lines so that more code can be displayed for easy reading. The following rules are recommended:

- Make a reasonable arrangement of blank lines according to the degree of relevance of neighboring content.
- Do not put two or more consecutive blank lines inside a function, a type definition, a macro, or an initialization expression.
- Do not use **three** or more consecutive blank lines.
- Do not add blank lines at the start and end of a code block defined by braces.

```c
ret = DoSomething();

if (ret != OK) {    // Bad: Return value judgment should follow the function call.
    return -1;
}
```

```c
int Foo(void)
{
    ...
}



int Bar(void)       // Bad: Use no more than two continuous blank lines.
{
    ...
}
```

```c
int Foo(void)
{
        
    DoSomething();  // Bad: The blank lines above and below are unnecessary.
    ...

}
```

900
# 3 Comments
N
NEEN 已提交
901

W
wusongqing 已提交
902 903
Generally, clear architecture and good symbol naming are recommended to improve code readability, and comments are provided only when necessary.

N
NEEN 已提交
904 905 906 907
Comments help readers quickly understand code. Therefore, **comments should be provided when necessary** for the sake of readers.

The comments must be concise, clear, and unambiguous, ensuring that the information is complete and not redundant.

W
wusongqing 已提交
908 909
**Comments are as important as code.**

W
wusongqing 已提交
910
When writing a comment, you need to step into the reader's shoes and use comments to express what the reader really needs. Comments are used to express the code functionality and intention, rather than repeating code.
911

W
wusongqing 已提交
912 913 914
When modifying the code, ensure that the comments are consistent. It is impolite to only modify code and not update the comments. This destroys the consistency between code and comments, and may cause confusion or even misleading.

Comment code in fluent **English**.
N
NEEN 已提交
915

W
wusongqing 已提交
916 917 918 919 920
Comments must be added in the following scenarios (including but not limited to the listed scenarios):
1. Functions in the external interface header file provided by the module
2. Global variables being defined
3. Core algorithms
4. A function that contains more than 50 lines
N
NEEN 已提交
921

922
## Comment Style
N
NEEN 已提交
923

W
wusongqing 已提交
924 925
In C code, both `/*` `*/` and `//` can be used. 

W
wusongqing 已提交
926
Comments can be classified into different types depending on the purpose and position, such as file header comments, function header comments, and general comments.
927

N
NEEN 已提交
928 929
Comments of the same type must keep a consistent style.

W
wusongqing 已提交
930
Note: The sample code used in this article sees extensive use of the '//' post-comment. This is only for better understanding, and does not mean that this comment style is better.
N
NEEN 已提交
931

932
## File Header Comments
N
NEEN 已提交
933

934
### Rule 3.1 Include the copyright license in the file header comments.
N
NEEN 已提交
935 936 937 938 939 940 941

/\*

* Copyright (c) 2020 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
W
wusongqing 已提交
942
* 
N
NEEN 已提交
943
* http://www.apache.org/licenses/LICENSE-2.0
W
wusongqing 已提交
944
* 
N
NEEN 已提交
945 946 947 948 949 950
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License. \*/

951
## Function Header Comments
N
NEEN 已提交
952

953
### Rule 3.2 Do not use empty function header comments with no content.
N
NEEN 已提交
954

W
wusongqing 已提交
955 956
Not all functions need function header comments.

N
NEEN 已提交
957 958
Function header comments must be added for any information that cannot be expressed just with function prototype.

W
wusongqing 已提交
959 960 961 962
Function header comments are placed above the function declaration or definition. 

Select and use one of the following styles: 

N
NEEN 已提交
963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986
**Use '//' to start the function header.**

```c
// Single-line function header
int Func1(void);

// Multi-line function header
// Second line
int Func2(void);
```

**Use '/\*' '\*/' to start the function header.**

```c
/* Single-line function header */
int Func1(void);

/*
 * Single-line or multi-line function header
 * Second line
 */
int Func2(void);
```

987 988
Use function names to describe functions, and only add function header comments if necessary.  

N
NEEN 已提交
989 990
Do not write useless or redundant function headers. Do not write empty function headers with no content.

W
wusongqing 已提交
991
The following content is **optional** in the function header comment: function description, return value, performance constraint, usage, memory convention, algorithm implementation, and reentering requirement.
992

N
NEEN 已提交
993 994 995 996 997 998 999
In the function interface declaration in the external header file of the module, the function header comment should clearly describe important and useful information.

Example:

```c
/*
 * The number of written bytes is returned. If -1 is returned, the write operation fails.
W
wusongqing 已提交
1000
 * Note that the memory buffer is released by the caller.
N
NEEN 已提交
1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020
 */
int WriteString(char *buf, int len);
```

Bad example:

```c
/*
 * Function name: WriteString
 * Function: Write a character string.
 * Parameter:
 * Return value:
 */
int WriteString(char *buf, int len);
```

Problems in the preceding example are as follows:

- The 'Parameter' and 'Return value' headings have no content.
- The function name has redundant information.
W
wusongqing 已提交
1021
- It does not clearly state the party that should release the buffer.
N
NEEN 已提交
1022

1023
## Code Comments
N
NEEN 已提交
1024

1025
### Rule 3.3 Place code comments above or to the right of the code.
N
NEEN 已提交
1026

1027
### Rule 3.4 Add a space between the comment character and the comment content, and one space between the comment and code if the comment is placed to the right of the code.
N
NEEN 已提交
1028

W
wusongqing 已提交
1029 1030
Comments placed above code should be indented to the same level as the code. 

N
NEEN 已提交
1031
Select and use one of the following styles:   
W
wusongqing 已提交
1032

N
NEEN 已提交
1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046
**Use '//' to start the comment.**

```c
// Single-line comment
DoSomething();

// Multi-line comment
// Second line
DoSomething();
```

**Use '/\*' '\*/' to start the comment.**

```c
W
wusongqing 已提交
1047
/* Single-line comment */
N
NEEN 已提交
1048 1049 1050 1051 1052 1053 1054 1055 1056
DoSomething();

/*
 * Single-/Multi-line comment
 * Second line
 */
DoSomething();
```

G
Gloria 已提交
1057
Leave at least one space between the code and the comment on the right. No more than four spaces are recommended.
W
wusongqing 已提交
1058 1059


N
NEEN 已提交
1060 1061 1062 1063 1064 1065 1066 1067 1068
You can use the extended Tab key to indent 1-4 spaces.

Select and use one of the following styles:

```c
int foo = 100;  // Comment on the right
int bar = 200;  /* Comment on the right */
```

W
wusongqing 已提交
1069 1070 1071 1072 1073
It is more appealing sometimes when the comment is placed to the right of code and the comments and code are aligned vertically. 

After the alignment, ensure that the comment is 1–4 spaces separated from the closest code line on the left.


N
NEEN 已提交
1074 1075 1076 1077 1078 1079 1080 1081 1082
Example:

```c
#define A_CONST 100         /* Related comments of the same type can be aligned vertically. */
#define ANOTHER_CONST 200   /* Leave spaces after code to align comments vertically. */
```

If the comment on the right exceeds the permitted line length, the comment can be placed above the code.

1083 1084 1085
### Rule 3.5 Delete unused code segments. Do not comment them out.

Code that is commented out cannot be maintained. If you attempt to restore the code, it is very likely to introduce ignorable defects.  
N
NEEN 已提交
1086 1087 1088 1089 1090

The correct method is to delete unnecessary code. If necessary, consider porting or rewriting the code.

Here, commenting out refers to the removal of code from compilation without actually deleting it. This is done by using /\* \*/, //, #if 0, #ifdef NEVER\_DEFINED, and so on.

1091
### Rec 3.1 Provide comments if `break` or `return` is not added to the end of the `case` statement block (fall-through).
N
NEEN 已提交
1092

W
wusongqing 已提交
1093 1094
Sometimes, the same thing is needed for multiple `case` tags. When a `case` statement ends without `break` or `return`, the statement in the next `case` tag will be executed. This is called "fall-through". 

W
wusongqing 已提交
1095
In this case, add comments for the "fall-through" to clearly express your intention, or at least explicitly specify the "fall-through".
N
NEEN 已提交
1096

W
wusongqing 已提交
1097
For example, to explicitly specify the "fall-through":
N
NEEN 已提交
1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113

```c
switch (var) {
    case 0:
        DoSomething();
        /* fall-through */
    case 1:
        DoSomeOtherThing();
        ...
        break;
    default: 
        DoNothing();
        break;
}
```

W
wusongqing 已提交
1114
If the `case` statement is empty, no comment is required to explain the "fall-through".
N
NEEN 已提交
1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127

```c
switch (var) {
    case 0:
    case 1:
        DoSomething();
        break;
    default:
        DoNothing();
        break;
}
```

1128
# 4 Header Files
N
NEEN 已提交
1129

W
wusongqing 已提交
1130
**For the C programming language, the design of the header file reflects most of the system design.**   
1131

N
NEEN 已提交
1132 1133
The correct use of the header file makes code more readable, reduces file size, and speeds up compilation and build performance.

W
wusongqing 已提交
1134
The following programming specifications aim to help you properly plan header files.
N
NEEN 已提交
1135

1136
## Header File Responsibility
N
NEEN 已提交
1137

W
wusongqing 已提交
1138 1139 1140 1141
A header file is an external interface of a module or file. 

The interface declaration for most functions (except inline functions) is suitable in the header file. Interface implementations are not allowed in the header file. 

W
wusongqing 已提交
1142
Header responsibility should be simple. A complex header file will make dependencies complex and cause a long compilation time.
N
NEEN 已提交
1143

W
wusongqing 已提交
1144
### <a name="a4-1"></a>Rec 4.1 For each .c file, provide a corresponding .h file, which is used to declare the interfaces that need to be provided externally.
N
NEEN 已提交
1145

W
wusongqing 已提交
1146
Generally, each .c file has a corresponding .h file (not necessarily with the same name), which is used to store the function declarations, macro definitions, and type definitions that are to be exposed externally.
N
NEEN 已提交
1147 1148
If a .c file does not need to open any interface externally, it should not exist.

W
wusongqing 已提交
1149
Exceptions: the entry point of the program (for example, the file where the main function is located), unit test code, and dynamic library code.
N
NEEN 已提交
1150

1151 1152
Example:  

W
wusongqing 已提交
1153
Content of **foo.h**:
N
NEEN 已提交
1154 1155 1156 1157 1158 1159 1160 1161 1162 1163

```c
#ifndef FOO_H
#define FOO_H

int Foo(void);  // Good: Declare an external interface in the header file.

#endif
```

W
wusongqing 已提交
1164
Content of **foo.c**:
N
NEEN 已提交
1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179

```c
static void Bar(void);  // Good: The declaration of the internal function is placed in the header of the .c file, declaring its static scope.

void Foo(void)
{
    Bar();
}

static void Bar(void)
{
    // Do something;
}
```

W
wusongqing 已提交
1180
Internally used functions declarations, macros, enums, structs, and others should not be placed in header files.
N
NEEN 已提交
1181

W
wusongqing 已提交
1182 1183
In some products, one .c file corresponds to two .h files. One is used to store external public interfaces, and the other is used to store definitions and declarations among others for internal use to limit the number of code lines in the .c file. 

W
wusongqing 已提交
1184
This style is not recommended. It is used only because the .c file is too large. You should consider splitting the .c file first.
N
NEEN 已提交
1185 1186
In addition, if private definitions and declarations are placed in independent header files, they technically cannot avoid inclusion.

W
wusongqing 已提交
1187
This rule, in turn, is not necessarily correct. Example:
W
wusongqing 已提交
1188 1189
Some simple header files, such as the command ID definition header file, do not need to have the corresponding .c file. 

N
NEEN 已提交
1190 1191
If a set of interface protocols has multiple instances and the interface is fixed, one .h file can have multiple .c files.

1192 1193 1194
### Rec 4.2 Use .h as the extension of the header file, rather than other unconventional extensions, for example, .inc.

Some products use .inc as the header file name extension, which does not comply with the C programming language. A header file using .inc as the file name extension usually indicates a private header file. 
N
NEEN 已提交
1195

1196
However, in practice, this recommendation is not followed properly. An .inc file is generally contained in multiple .c files. It is not recommended that private definitions be stored in header files. For details, see [Rec 4.1](#a4-1).
N
NEEN 已提交
1197

1198 1199 1200
## Header File Dependency

The header file contains a dependency, and the dependency should be stable.  
N
NEEN 已提交
1201 1202 1203 1204 1205

Generally, an unstable module depends on a stable module. When the unstable module changes, the build of the stable module is not affected.

Dependency direction is as follows: Products depend on the platform, and the platform depends on the standard library.

1206 1207
In addition to unstable modules depending on stable modules, each module depends on the interface. In this way, in case of any internal implementation changes to one module, users do not need to recompile another module.  

W
wusongqing 已提交
1208
It is assumed that the interface is the most stable.
N
NEEN 已提交
1209

1210 1211 1212
### Rule 4.1 Forbid cyclic dependency of header files.

Cyclic dependency (also known as a circular dependency) of header files means that a.h contains b.h, b.h contains c.h, and c.h contains a.h. If any header file is modified, all code containing a.h, b.h, and c.h needs to be recompiled.  
N
NEEN 已提交
1213 1214 1215 1216 1217

For a unidirectional dependency: a.h contains b.h, b.h contains c.h, and c.h does not contain any header file, modifying a.h does not mean a need to recompile the source code for b.h or c.h.

The cyclic dependency of header files reflects an obviously unreasonable architecture design, which can be avoided through optimization.

1218
### Rule 4.2 Include the internal #include protection character (#define protection) in the header file.
N
NEEN 已提交
1219 1220 1221 1222 1223

To prevent header files from being included multiple times, all header files should be protected by #define. Do not use #pragma once.

When defining a protection character, comply with the following rules:

W
wusongqing 已提交
1224
- Use a unique name for the protection character in the format of subsystem\_component\_file.
N
NEEN 已提交
1225 1226
- Do not place code or comments before or after the protected part, except for file header comments.

W
wusongqing 已提交
1227
Assume that the **timer.h** file of the timer component of the util subsystem is stored in the **timer/include/timer.h** directory. If `TIME_H` is used as the protection character, name conflicts may occur. Use the following protection characters instead:
N
NEEN 已提交
1228
```c
W
wusongqing 已提交
1229 1230
#ifndef UTIL_TIMER_TIMER_H
#define UTIL_TIMER_TIMER_H
N
NEEN 已提交
1231 1232 1233

...

W
wusongqing 已提交
1234
#endif // UTIL_TIMER_TIMER_H
N
NEEN 已提交
1235 1236
```

1237 1238 1239 1240 1241
### Rule 4.3 Do not reference external function interfaces and variables by using declaration.

You can use the interfaces provided by other modules or files only by using header files. 

Using external function interfaces and variables with an extern declaration may cause inconsistency between declarations and definitions when external interfaces are changed.  
N
NEEN 已提交
1242 1243 1244 1245

In addition, this kind of implicit dependency may cause architecture corruption.

Cases that do not comply with specifications:   
1246

W
wusongqing 已提交
1247
Content of **a.c**:
N
NEEN 已提交
1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258

```c
extern int Foo(void);   // Bad: Reference external functions by using the extern declaration.
void Bar(void)
{
    int i = Foo();  // Here, the external interface Foo is used.
    ...
}
```

It should be changed to:   
W
wusongqing 已提交
1259
Content of **a.c**:
N
NEEN 已提交
1260 1261

```c
W
wusongqing 已提交
1262
#include "b.h"      // Good: Use the interfaces provided by another .c file by including the header file.
N
NEEN 已提交
1263 1264 1265 1266 1267 1268 1269
void Bar(void)
{
    int i = Foo();
    ...
}
```

W
wusongqing 已提交
1270
Content of **b.h**:
N
NEEN 已提交
1271 1272 1273 1274 1275

```c
int Foo(void);
```

W
wusongqing 已提交
1276
Content of **b.c**:
N
NEEN 已提交
1277 1278 1279 1280 1281 1282 1283 1284 1285

```c
int Foo(void)
{
    // Do something
}
```

In some scenarios, if internal functions need to be referenced with no intrusion to the code, the extern declaration mode can be used.   
1286

W
wusongqing 已提交
1287
Example:
1288 1289 1290

When performing unit testing on an internal function, you can use the extern declaration to reference the tested function. 

N
NEEN 已提交
1291 1292
When a function needs to be stubbed or patched, the function can be declared using extern.

1293
### Rule 4.4 Do not include header files in extern "C".
N
NEEN 已提交
1294

W
wusongqing 已提交
1295
If a header file is included in extern "C", extern "C" may be nested. Some compilers restrict the number of nesting layers of extern "C". Too many nesting layers may cause compilation errors.
N
NEEN 已提交
1296

W
wusongqing 已提交
1297
extern "C" usually occurs in mixed programming using both C and C++. If extern "C" includes a header file, the original intent behind the header file may be hindered, for example, when linkage specifications are changed incorrectly.
N
NEEN 已提交
1298

W
wusongqing 已提交
1299 1300
Assume that there are two header files: **a.h** and **b.h**.
Content of **a.h**:
N
NEEN 已提交
1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311

```c
...
#ifdef __cplusplus
void Foo(int);
#define A(value) Foo(value)
#else
void A(int)
#endif
```

W
wusongqing 已提交
1312
Content of **b.h**:
N
NEEN 已提交
1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327

```c
...
#ifdef __cplusplus
extern "C" {
#endif

#include "a.h"
void B(void);

#ifdef __cplusplus
}
#endif
```

W
wusongqing 已提交
1328
When you use the C++ preprocessor to expand **b.h**, the following information is displayed:
N
NEEN 已提交
1329 1330 1331 1332 1333 1334 1335 1336

```c
extern "C" {
    void Foo(int);
    void B(void);
}
```

1337 1338 1339
In the **a.h** file, the **Foo** function is intended to be a C++ free function following the C++ specifications. 

However, in the **b.h** file, because `#include "a.h"` is placed inside `extern "C"`, the linking specification of the **Foo** function is changed incorrectly.
N
NEEN 已提交
1340

W
wusongqing 已提交
1341
Exceptions: In the C++ compilation environment, if you want to reference a header file written in pure C, a non-intrusive approach is to exclude the C header file from `extern "C"`.
N
NEEN 已提交
1342

1343
# 5 Functions
N
NEEN 已提交
1344

W
wusongqing 已提交
1345
Functions help avoid repeated code and increase reusability. Functions are layered to reduce complexity and hide implementation details, making programs more modular and facilitating code reading and maintenance.
N
NEEN 已提交
1346

W
wusongqing 已提交
1347
Functions should be concise and short.
1348

N
NEEN 已提交
1349 1350
One function completes only one thing.

1351
## Function Design
N
NEEN 已提交
1352

W
wusongqing 已提交
1353
The essence of function design is to write clean functions and organize code effectively. The code should be simple and not conceal the designer's intention, using clean abstractions and straightforward control statements to organize the function naturally.
N
NEEN 已提交
1354

1355
### Rule 5.1 Avoid long functions and ensure that functions contain no more than 50 lines (excluding blank lines and comments).
N
NEEN 已提交
1356

W
wusongqing 已提交
1357
A function should be able to be displayed on one screen (fewer than 50 lines). It does only one thing and does it well.
N
NEEN 已提交
1358

W
wusongqing 已提交
1359
A long function usually means that it aims to implement complex functionalities or contains excess details.
N
NEEN 已提交
1360

W
wusongqing 已提交
1361
Exceptions:
1362 1363 1364

Considering the code's aggregation and functionality, some functions may exceed 50 lines, but only if the code is readable and concise.  

N
NEEN 已提交
1365 1366
These exceptions should be minimal, such as specific algorithm processing.

1367 1368
Even if a large function works well in the moment, once someone modifies it, new problems may occur. It may even cause bugs that are difficult to discover.  

W
wusongqing 已提交
1369
It is recommended that you split the code into several functions that are simpler and easier to manage so that others can easily read and modify the code.
N
NEEN 已提交
1370

1371
### Rule 5.2 Avoid nesting a code block more than four times within a function.
N
NEEN 已提交
1372

W
wusongqing 已提交
1373
The nested code block depth of a function refers to the layered depth of a code control block (created by statements such as `if`, `for`, `while`, and `switch`).
1374

W
wusongqing 已提交
1375
Each layer of nesting increases the difficulty in reading the code.
1376

W
wusongqing 已提交
1377
Further functional decomposition should be done for better understanding.
N
NEEN 已提交
1378

W
wusongqing 已提交
1379 1380
Using `guard clauses` can effectively reduce the nesting layers of the `if` statements. Example:
Three nesting layers are used originally:
N
NEEN 已提交
1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394

```c
int Foo(...)
{
    if (received) {
        type = GetMsgType(msg);
        if (type != UNKNOWN) {
            return DealMsg(...);
        }
    }
    return -1;
}
```

W
wusongqing 已提交
1395
Two nesting layers after code reconstruction using `guard clauses`:
N
NEEN 已提交
1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412

```c
int Foo(...)
{
    if (!received) {    // Good: Use the 'guardian statement'.
        return -1;
    }
    
    type = GetMsgType(msg);
    if (type == UNKNOWN) {
        return -1;
    }
    
    return DealMsg(..);
}
```

W
wusongqing 已提交
1413
Exceptions:
1414

W
wusongqing 已提交
1415
Considering the code's aggregation and functionality, some functions may contain 4 or more nesting layers, but only if the code is readable and concise.
1416

N
NEEN 已提交
1417 1418
These exceptions should be rare.

1419
### Rec 5.1 Process all returned error codes.
N
NEEN 已提交
1420 1421 1422 1423 1424 1425 1426

A function (in a standard library, a third-party library, or a user-defined function) must be able to indicate errors. This can be done by using error tags, special return data, or other means. No matter when a function provides such a mechanism, the caller should immediately check the error indication after the function returns.

Example:

```c
char fileHead[128];
W
wusongqing 已提交
1427
ReadFileHead(fileName, fileHead, sizeof(fileHead)); // Bad: The return value is not checked.
N
NEEN 已提交
1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443

DealWithFileHead(fileHead, sizeof(fileHead));       // The 'fileHead' is possibly invalid.
```

The correct format is as follows:

```c
char fileHead[128];
ret = ReadFileHead(fileName, fileHead, sizeof(fileHead));
if (ret != OK) {                // Good: Ensure that the 'fileHead' is written.
    return ERROR;
}

DealWithFileHead(fileHead, sizeof(fileHead));       // Process the file header.
```

W
wusongqing 已提交
1444
If the return value of a function is ignored and `void` is returned frequently, check whether the return value of the function is designed properly.
1445

N
NEEN 已提交
1446 1447
Only if the caller of a function really doesn't need a return value, should you design the function to return `void`.

1448
## Function Parameters
N
NEEN 已提交
1449

1450
### Rec 5.2 Use the return value instead of the output parameter when designing a function.
N
NEEN 已提交
1451 1452 1453

Using return values rather than output parameters improves readability and usually provides the same or better performance.

W
wusongqing 已提交
1454 1455 1456 1457 1458
Readability can be improved by naming functions such as GetXxx, FindXxx, IsXxx, OnXxx, or directly using a single noun, to directly return the corresponding object.

Exceptions:
1. When multiple values are returned, you can design an output parameter for the function.
2. If memory allocation is involved, you can design an output parameter. The caller passes the allocated memory as an output parameter, and memory allocation is not performed in the function.
N
NEEN 已提交
1459

1460
### Rec 5.3 Define function parameters in the sequence of input, output, and input/output parameters.
W
wusongqing 已提交
1461 1462 1463

You are advised to define function parameters in the sequence of input, output, and input/output parameters.

1464
### Rule 5.3 Provide a release function if allocation of resources, such as memory, locks, and queues, is involved.
W
wusongqing 已提交
1465 1466 1467

Resources should be released from where they are applied for. If a function applies for resources, the module must provide resource functions.

1468 1469 1470
### Rec 5.4 Use strongly typed parameters. Do not use void\*.

While different languages have their own views on strong typing and weak typing, it is generally believed that C/C++ is a strongly typed language. Since we use such a strongly typed language, we should keep this style.  
N
NEEN 已提交
1471 1472 1473

The advantage of this strongly typed style is to prevent evasive errors by catching errors at the compilation stage.

W
wusongqing 已提交
1474
Strong types help the compiler find more errors.Pay attention to the usage of the `FooListAddNode` function in the following code:
N
NEEN 已提交
1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498

```c
struct FooNode {
    struct List link;
    int foo;
};

struct BarNode {
    struct List link;
    int bar;
}

void FooListAddNode(void *node) // Bad: Here, the void * type is used to pass parameters.
{
    FooNode *foo = (FooNode *)node;
    ListAppend(&g_fooList, &foo->link);
}

void MakeTheList(...)
{
    FooNode *foo;
    BarNode *bar;
    ...

W
wusongqing 已提交
1499
    FooListAddNode(bar);        // Wrong: In this example, the bar parameter rather than the foo parameter is passed.No error is reported immediately and issues may occur as a result.
N
NEEN 已提交
1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513
}

```

The preceding problems may be difficult to expose and are more destructive than compiler errors.   
If the parameter type of `FooListAddNode` is specified clearly, instead of with the `void *` type, the preceding problem can be detected during compilation.

```c
void FooListAddNode(FooNode *foo)
{
    ListAppend(&g_fooList, &foo->link);
}
```

W
wusongqing 已提交
1514
Exceptions: For some generic interfaces, you can use the input parameter `void *` to pass different types of pointers.
N
NEEN 已提交
1515

1516
### Rec 5.5 It is the caller's responsibility to check the validity of internal function parameters of a module.
N
NEEN 已提交
1517

W
wusongqing 已提交
1518
Validity check must be performed on parameters passed from external modules to protect programs from being damaged by invalid input data.
1519

N
NEEN 已提交
1520 1521
When calling internal functions, by default, the caller is responsible for ensuring the validity of any returned data. If the callee takes responsibility for checking data validity, checks may be performed multiple times and redundant code is generated. This is not concise.

W
wusongqing 已提交
1522
When the caller ensures the validity of any received data, this contractual programming makes logic simpler and code more readable.
1523

N
NEEN 已提交
1524 1525 1526 1527 1528 1529 1530 1531
Example:

```c
int SomeProc(...)
{
    int data;
    
    bool dataOK = GetData(&data);       // Get data.
W
wusongqing 已提交
1532
    if (!dataOK) {                      // Check the result of the previous step to ensure data validity.
N
NEEN 已提交
1533 1534 1535 1536 1537 1538 1539 1540 1541
        return -1;
    }

    DealWithData(data);                 // Call the data processing function.
    ...
}

void DealWithData(int data)
{
W
wusongqing 已提交
1542
    if (data < MIN || data > MAX) {     // Bad: The caller has already ensured data validity.
N
NEEN 已提交
1543 1544 1545 1546 1547 1548 1549
        return;
    }

    ...
}
```

1550
### Rec 5.5 Declare the pointer argument of a function as 'const' if it is not used to modify the pointed object.
N
NEEN 已提交
1551 1552 1553 1554 1555 1556 1557 1558 1559

The const pointer argument, which restricts the function from modifying the object through the pointer, makes code stronger and safer.

Example: In the example of the strncmp in the 7.21.4.4 of the C99 standard, the invariant parameter is declared as const.

```c
int strncmp(const char *s1, const char *s2, size_t n); // Good: The invariant parameter is declared as const.
```

W
wusongqing 已提交
1560
Note: Whether to declare the pointer parameter as `const` depends on the function design, but not on whether there is a "modify object" action in the function entity.
N
NEEN 已提交
1561

1562
### Rec 5.6 Include no more than 5 parameters in a function.
N
NEEN 已提交
1563

G
Gloria 已提交
1564
If a function has too many parameters, the function is easy to be affected by changes in external code, hindering maintenance. Too many function parameters will also increase the workload for testing.
N
NEEN 已提交
1565 1566 1567 1568 1569 1570

The number of parameters in a function must not exceed 5. If the number of parameters exceeds 5, consider the following:

- Check whether the function can be split.
- Check whether any related parameters can be combined and defined as a struct.

1571
## Inline Functions
N
NEEN 已提交
1572

1573
An inline function is a function optimization method introduced by C99. Function inlining can eliminate the overhead of function calls; thanks to inlining, combination with the called code is implemented, so that the compiler can achieve further code optimization from a larger perspective. The inline function is similar to a function-like macro. For details, see [Rec 6.1](#a6-1).
N
NEEN 已提交
1574

1575
### Rec 5.7 Include no more than 10 lines in an inline function (excluding blank lines and comments).
N
NEEN 已提交
1576

W
wusongqing 已提交
1577 1578 1579 1580 1581
Defining a function as an inline function generally aims to improve performance, though it may fail to do so.If the function body is short, function inlining can effectively reduce the size of the target code and improve the function execution efficiency. 

Vice versa, if the function body is large, inlining will cause expansion of the target code, especially when there are many call points.


N
NEEN 已提交
1582 1583
It is recommended that inline functions be controlled to within **10** lines.

W
wusongqing 已提交
1584
Do not abuse inline functions to improve performance. Avoid premature optimization. In general, a function can be defined as an inline function only when actual test data proves that the inlining achieves higher performance. Functions such as setter and getter functions, which are short and called frequently, can be defined as inline functions.
N
NEEN 已提交
1585

1586
### Rule 5.3 Define inline functions that will be called by multiple source files in the header file.
N
NEEN 已提交
1587

W
wusongqing 已提交
1588 1589
Inline functions are unfolded in compilation. Therefore, the inline function definition must be visible in each source file that calls this function. 

W
wusongqing 已提交
1590
As shown in the following code, **inline.h** contains the declaration of the `SomeInlineFunc` function but not the definition. The **other.c** file includes **inline.h**. As a result, inlining fails when `SomeInlineFunc` is called.
N
NEEN 已提交
1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616

inline.h

```c
inline int SomeInlineFunc(void);
```

inline.c

```c
inline int SomeInlineFunc(void)
{
    // Implementation code
}
```

other.c

```c
#include "inline.h"
int OtherFunc(void)
{
    int ret = SomeInlineFunc();
}
```

W
wusongqing 已提交
1617
Due to this restriction, if multiple source files need to call the same inline function, the definition of the inline function must be placed in the header file.
1618

N
NEEN 已提交
1619 1620
The inline function implementation in **gnu89** differs from that in the **C99** standard. For compatibility, you can declare the function as **static inline**.

1621
# 6 Macros
N
NEEN 已提交
1622

1623
## Function-like Macros
N
NEEN 已提交
1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636

A function-like macro is a macro (as shown in the following example) similar to a function. It contains several statements to implement a specific function.

```c
#define ASSERT(x) do { \
    if (!(x)) { \
        printk(KERN_EMERG "assertion failed %s: %d: %s\n", \
              __FILE__, __LINE__, #x); \
        BUG(); \
    } \
} while (0)
```

W
wusongqing 已提交
1637
### <a name="a6-1"></a>Rec 6.1 Use functions instead of function-like macros.
N
NEEN 已提交
1638

W
wusongqing 已提交
1639 1640
Before defining a function-like macro, consider whether it can be replaced with a function. If yes, you are advised to use a function for replacement.

N
NEEN 已提交
1641 1642 1643
The disadvantages of the function-like macro are as follows:

- Function-like macros haves no type check, which is not as strict as the function call check. For the example code, see [Below](#macro_lack_of_type_check__example).
1644 1645
- If macro parameters are not calculated during macro expansion, unexpected results may be generated. For details, see [Rule 6.1](#r6-1) and [Rule 6.3](#r6-3).
- A macro has no independent scope. When it is used together with control flow statements, unexpected results described in [Rule 6.2](#r6-2) may be generated.
W
wusongqing 已提交
1646
- There are high skill requirements on the proper use of macros (for example, the usage of `#` and wide use of parentheses), which reduces readability.
N
NEEN 已提交
1647
- Extensions of some macros can only be implemented by specific compilers in specific scenarios, such as `statement expression` of `gcc`, reducing the portability.
W
wusongqing 已提交
1648
- After the macro is expanded during precompilation, it is invisible during subsequent compilation, linking, and debugging. Besides, macros that contain multiple lines are expanded into a line.
N
NEEN 已提交
1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678
- Macros containing a large number of statements must be expanded at each call point. If there are many call points, the code will be expanded.

<a name="macro_lack_of_type_check__example"></a>Example code of a function-like macro lacking type check:

```c
#define MAX(a, b)   (((a) < (b)) ? (b) : (a))

int Max(int a, int b)
{
    return (a < b) ? b : a;
}

int TestMacro(void)
{
    unsigned int a = 1;
    int b = -1;

    (void)printf("MACRO: max of a(%u) and b(%d) is %d\n", a, b, MAX(a, b));
    (void)printf("FUNC : max of a(%u) and b(%d) is %d\n", a, b, Max(a, b));
    return 0;
}
```

Due to the lack of type check, the comparison between `a` and `b` in `MAX` is changed to a comparison ignoring the sign status. The result is **a \< b**. The output is as follows:

```
MACRO: max of a(1) and b(-1) is -1
FUNC : max of a(1) and b(-1) is 1
```

W
wusongqing 已提交
1679
The function does not have the preceding macro disadvantages. However, compared with macros, the biggest disadvantage of functions is its low execution efficiency (increasing the overhead of function calls and the difficulty of compiler optimization).
N
NEEN 已提交
1680 1681 1682 1683 1684 1685
Therefore, the C99 standard introduces inline functions (gcc introduces inline functions ahead of this standard).

The inline function is similar to the macro, as it is also expanded at the call point. The difference is that inline functions are expanded during compilation.   
Inline functions have the advantages of both functions and macros:

- Strict type checking is performed for inline functions and functions.
W
wusongqing 已提交
1686
- Each input parameter of an inline function or function is calculated only once.
N
NEEN 已提交
1687 1688 1689 1690
- Inline functions are unfolded in place and there is no overhead for function calls.
- Inline functions are better optimized than standard functions.

For performance-sensitive code, consider using inline functions instead of function-like macros.   
W
wusongqing 已提交
1691
Functions and inline functions cannot completely replace function-like macros, since function-like macros are more suitable for certain scenarios.
N
NEEN 已提交
1692 1693 1694 1695 1696 1697 1698
For example, in a log scenario, using a function-like macro with variable parameters and default parameters is more convenient.

```c
int ErrLog(const char *file, unsigned long line, const char *fmt, ...);
#define ERR_LOG(fmt, ...) ErrLog(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
```

W
wusongqing 已提交
1699
### <a name="r6-1"></a>Rule 6.1 Use complete parentheses for macro parameters when defining a macro.
N
NEEN 已提交
1700

1701 1702
The macro parameter is replaced by text only when the macro is expanded. The value is calculated when the macro is compiled. After the text replacement, the statements contained in the macro are combined with called code.  

N
NEEN 已提交
1703 1704 1705 1706 1707
The expression after combination may result in a different result than expected, especially when the macro parameter is in an expression.

The following is an incorrect format:

```c
W
wusongqing 已提交
1708
#define SUM(a, b) a + b         // Bad
N
NEEN 已提交
1709 1710
```

1711 1712 1713 1714
When the macro is used, the execution result is inconsistent with the expected result. 

`100 / SUM(2, 8)` is expanded to `(100 / 2) + 8`. The expected result is `100 / (2 + 8)`. 

N
NEEN 已提交
1715 1716 1717
This problem can be solved by adding parentheses to the entire expression, as shown in the following:

```c
W
wusongqing 已提交
1718
#define SUM(a, b) (a + b)       // Bad
N
NEEN 已提交
1719 1720
```

1721 1722
However, this method has the following problems:  

N
NEEN 已提交
1723 1724 1725 1726 1727
`SUM(1 << 2, 8)` is extended to `1 << (2 + 8)` (because the priority of `<<` is lower than that of `+`), which is inconsistent with the expected result `(1 << 2) + 8`.

To solve this problem, add parentheses to each macro parameter, as shown in the following:

```c
W
wusongqing 已提交
1728
#define SUM(a, b) (a) + (b)     // Bad
N
NEEN 已提交
1729 1730 1731 1732 1733 1734 1735 1736 1737 1738
```

The third scenario is as follows: `SUM(2, 8) * 10` . The result after the extension is `(2) + ((8) * 10)`, which is inconsistent with the expected result `(2 + 8) * 10`.

In conclusion, the correct format is as follows:

```c
#define SUM(a, b) ((a) + (b))   // Good.
```

W
wusongqing 已提交
1739
Avoid abusing parentheses. As shown in the following, adding parentheses to a single identifier or a positive number is meaningless.
N
NEEN 已提交
1740 1741 1742 1743 1744 1745 1746 1747 1748 1749

```c
#define SOME_CONST      100     // Good: No parentheses needed for a single positive number.
#define ANOTHER_CONST   (-1)    // Good: Parentheses needed for a negative number.

#define THE_CONST SOME_CONST    // Good: No parentheses needed for a single identifier.
```

Notes:

W
wusongqing 已提交
1750 1751
- Do not add parentheses to macro parameters when they are involved in the '#' or '##' operation.
- Do not add parentheses to macro parameters when they are used for string concatenation.
N
NEEN 已提交
1752 1753 1754 1755 1756 1757 1758 1759 1760 1761
- If a macro parameter is used as a separate part in one side of an assignment expression (including +=, -=, etc.), parentheses are not required.
- If a macro parameter is used as a separate part in comma expressions, functions or macro call lists, parentheses are not required.

Example:

```c
#define MAKE_STR(x) #x                  // No parentheses for 'x'

#define HELLO_STR(obj) "Hello, " obj    // No parentheses for 'obj'

W
wusongqing 已提交
1762
#define ADD_3(sum, a, b, c) (sum = (a) + (b) + (c)) // 'a', 'b', and 'c' need parentheses, whereas 'sum' does not.
N
NEEN 已提交
1763

W
wusongqing 已提交
1764
#define FOO(a, b) Bar((a) + 1, b)       // 'a' needs parentheses, whereas 'b' does not.
N
NEEN 已提交
1765 1766
```

W
wusongqing 已提交
1767
### <a name="r6-2"></a>Rule 6.2 Place implementation statements of function-like macros that contain multiple statements in a `do-while(0)`.
N
NEEN 已提交
1768

W
wusongqing 已提交
1769
Macros do not have code blocks. When a macro is expanded at the call point, the expressions and variables defined in the macro are integrated into the calling code. As a result, variable name conflict and segmentation of macro statements may occur. Use `do-while(0)` to add a boundary to the macro so that the macro has an independent scope. In addition, a single statement can be formed by combining the macro with a semicolon (;) to avoid this problem.
N
NEEN 已提交
1770

W
wusongqing 已提交
1771
Incorrect example:
N
NEEN 已提交
1772 1773

```c
W
wusongqing 已提交
1774
// Not Good
N
NEEN 已提交
1775 1776 1777 1778 1779
#define FOO(x) \
    (void)printf("arg is %d\n", (x)); \
    DoSomething((x));
```

W
wusongqing 已提交
1780
When the macro is called as shown in the following example code, the `for` loop only executes the first statement of the macro, and the next statement of the macro is executed only after the loop ends.
N
NEEN 已提交
1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795

```c
for (i = 1; i < 10; i++)
    FOO(i);
```

To solve the preceding problem, use braces to enclose the statements defined by `FOO`.

```c
#define FOO(x) { \
    (void)printf("arg is %d\n", (x)); \
    DoSomething((x)); \
}
```

1796 1797
The brackets are not associated with semicolons (;). The semicolon following the braces is another statement.  

N
NEEN 已提交
1798 1799 1800 1801 1802 1803 1804 1805 1806
In the following code example, the "suspended else' compilation error message is displayed.

```c
if (condition)
    FOO(10);
else
    FOO(20);
```

W
wusongqing 已提交
1807
The correct format is to wrap the executed body using a `do-while(0)`, as shown in the following:
N
NEEN 已提交
1808 1809

```c
W
wusongqing 已提交
1810
// Good
N
NEEN 已提交
1811 1812 1813 1814 1815 1816
#define FOO(x) do { \
    (void)printf("arg is %d\n", (x)); \
    DoSomething((x)); \
} while (0)
```

W
wusongqing 已提交
1817
Exceptions:
N
NEEN 已提交
1818 1819

- Macros that contain 'break' or 'continue' statements can be treated as exceptions. Do use these macros carefully.
W
wusongqing 已提交
1820 1821
- An exception can be made when the macro contains an incomplete statement. For example, use a macro to encapsulate the conditional part of the `for` loop.
- An exception can be a non-multiple statement, or a single `if`, `for`, `while`, or `switch` statement.
N
NEEN 已提交
1822 1823 1824

### <a name="r6-3"></a>Rule 6.3 Do not pass expressions with side effects to a function-like macro.

1825 1826
Since macros are replaced by text, if a function-like macro uses the same macro parameter multiple times and transfers expressions with side effects as macro parameters, unexpected results may occur.  

N
NEEN 已提交
1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845
As shown in the following example, the macro `SQUARE` is normal, but the `a++` expression with side effects is passed to the macro. As a result, the value of `a` is different from the expected value after the `SQUARE` macro is executed.

```c
#define SQUARE(a) ((a) * (a))

int a = 5;
int b;
b = SQUARE(a++);    // Bad: 'a' is added twice.
```

`SQUARE(a++)` is expanded to `((a++) * (a++))` the variable `a` is added twice, and its value is `7` instead of the expected `6`.

The correct format is as follows:

```c
b = SQUARE(a);
a++; // Result: a = 6, which is added only once.
```

1846 1847
In addition, if the macro parameter contains a function call, the function may be called repeatedly after the macro is expanded.  

N
NEEN 已提交
1848 1849
If the function execution results are the same, it is a waste; if the results are different, the execution result may not meet the expected value.

1850
### Rec 6.2 Exercise caution when you use the statements such as `return`, `goto`, `continue`, and `break` in a function-like macro definition.
N
NEEN 已提交
1851

W
wusongqing 已提交
1852
Although process changing statements, such as `return`, `goto`, `continue`, and `break`, in a macro can simplify the code, they hide the real process, which hinders understanding and easily causes resource leakage.
N
NEEN 已提交
1853

W
wusongqing 已提交
1854
First, the macro encapsulation of the `return` statement can easily lead to excessive encapsulation and use.
N
NEEN 已提交
1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871
As shown in the following code, the judgment of `status` is a part of the main process. After being encapsulated in macros, the purpose is not intuitive. The `RETURN_IF` macro is ignored, causing a confused understanding.

```c
#define LOG_AND_RETURN_IF_FAIL(ret, fmt, ...) do { \
    if ((ret) != OK) {                             \
        (void)ErrLog(fmt, ##__VA_ARGS__);          \
        return (ret);                              \
    }                                              \
} while (0)

#define RETURN_IF(cond, ret) do {                  \
    if (cond) {                                    \
        return (ret);                              \
    }                                              \
} while (0)

ret = InitModuleA(a, b, &status);
W
wusongqing 已提交
1872
LOG_AND_RETURN_IF_FAIL(ret, "Init module A failed!"); // OK
N
NEEN 已提交
1873 1874 1875 1876

RETURN_IF(status != READY, ERR_NOT_READY);  // Bad: The most important logic is not obvious.

ret = InitModuleB(c);
W
wusongqing 已提交
1877
LOG_AND_RETURN_IF_FAIL(ret, "Init module B failed!"); // OK
N
NEEN 已提交
1878 1879
```

W
wusongqing 已提交
1880
Second, if `return` is encapsulated in a macro, it may also cause a memory leak. Example:
N
NEEN 已提交
1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897

```c
#define CHECK_PTR(ptr, ret) do { \
    if ((ptr) == NULL) { \
        return (ret); \
    } \
} while (0)

...

mem1 = MemAlloc(...);
CHECK_PTR(mem1, ERR_CODE_XXX);

mem2 = MemAlloc(...);
CHECK_PTR(mem2, ERR_CODE_XXX);  // Wrong: Memory leak.
```

W
wusongqing 已提交
1898
If `mem2` fails to apply for memory, `CHECK_PTR` will return a message instead of releasing `mem1`.
1899

N
NEEN 已提交
1900 1901
Besides, the name of the `CHECK_PTR` macro is not good. The macro name only reflects the check action and does not specify the result. Readers can see that a failure is returned when the pointer is null only after viewing the macro implementation. It's not inherently obvious.

W
wusongqing 已提交
1902
In summary, it is not recommended to encapsulate process changing statements, such as `return`, `goto`, `continue`, and `break`, in macro definitions.
1903

W
wusongqing 已提交
1904
However, these macros can be used in special scenarios, such as return value judgment.
N
NEEN 已提交
1905

W
wusongqing 已提交
1906
Note: **Macro names must contain descriptive keywords if process changing statements, such as `return`, `goto`, `continue`, and `break`, are used.**
N
NEEN 已提交
1907

1908
### Rec 6.3 Include no more than 10 lines in a function-like macro (excluding blank lines and comments).
N
NEEN 已提交
1909

W
wusongqing 已提交
1910
A function-like macro is more difficult to debug and locate than a function, especially when the macro is too long.
N
NEEN 已提交
1911 1912
Macro expansion will also lead to more compiled code. It is recommended that function-like macros contain no more than 10 lines.

1913
# 7 Variables
N
NEEN 已提交
1914 1915

In C language coding, variables are the most important except for functions.   
1916 1917 1918

When using a variable, you should always follow the principle of "single responsibility". 

N
NEEN 已提交
1919 1920
By scope, variables can be classified into global variables and local variables.

1921 1922 1923
## Global Variables

Do not use or avoid using global variables. 
N
NEEN 已提交
1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934

In program design, global variables are variables that are accessible to all scopes. Using unnecessary global variables is generally considered a bad habit.

Disadvantages of global variables:

- Destroys the independence and portability of a function. Functions can be dependent on global variables and increased coupling results.
- Reduces readability and maintainability. When multiple functions read and write to global variables, their values may not be determinate, which is unfavorable for comprehension and maintenance.
- In a concurrent programming environment, global variables will hinder reentry of functions. Additional synchronization protection must be added to ensure data security.

If unavoidable, the read and write of global variables should be encapsulated in a centralized manner.

1935
### Rule 7.1 Do not use global variables as interfaces between modules.
N
NEEN 已提交
1936 1937

Global variables are for the internal implementation of modules and should not be exposed as interfaces.   
1938

N
NEEN 已提交
1939 1940
Global variables should be as centralized as possible. If the data of this module needs to be disclosed to external modules, a function as an interface to this data should be provided.

1941 1942 1943
## Local Variables

### Rule 7.2 Do not use uninitialized variables as rvalues.
N
NEEN 已提交
1944

1945
The variable here refers to a local dynamic variable, and also includes a memory block obtained on a memory heap.  
N
NEEN 已提交
1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971

Because their initial values are unpredictable, it is prohibited to use them directly as rvalues without effective initialization.

```c
void Foo(...)
{
    int data;
    Bar(data);  // Bad: Uninitialized variables are used as rvalues.
    ...
}
```

If there are different branches, ensure that all branches are initialized before being used as rvalues.

```c
void Foo(...)
{
    int data;
    if (...) {
        data = 100;
    }
    Bar(data);  // Bad: This value is not initialized in some branches.
    ...
}
```

1972 1973
Uninitialized rvalues can be found by generic static check tools. 

N
NEEN 已提交
1974 1975
For example, the PCLint tool reports a warning for the following two examples.

1976 1977 1978
> Warning 530: Symbol 'data' (line ...) not initialized 
>
> Warning 644: Variable 'data' (line ...) may not have been initialized
N
NEEN 已提交
1979

1980
### Rule 7.3 Forbid invalid and redundant variable initialization.
N
NEEN 已提交
1981

W
wusongqing 已提交
1982
If the initial value is not determined before initialization is performed, it is not concise or secure and may cause problems that are more difficult to discover.
N
NEEN 已提交
1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026

Common redundant initialization:

```c
int cnt = 0;    // Bad: Redundant initialization. It will be overwritten by later initialization.
...
cnt = GetXxxCnt();
...
```

Variables with conditional values can be initialized to default values during definition.

```c
char *buf = NULL;   // Good: NULL as the default value
if (condition) {
    buf = malloc(MEM_SIZE);
}
...
if (buf != NULL) {  // Check whether memory has been allocated.
    free(buf);
}
```

Even worse, redundant clearing for arrays may affect the performance.

```c
char buf[VERY_BIG_SIZE] = {0};  
memset(buf, 0, sizeof(buf));    // Bad: Redundant clearing
```

Invalid initialization, which hides a more severe problem:

```c
void Foo(...)
{
    int data = 0;   // Bad: regular initialization

    UseData(data);          // UseData should be placed after GetData.
    data = GetData(...);    // Get data.
    ...
}
```

In the preceding code, if 0 is not assigned before initialization, the static check tool can help find the problem of "direct use without being initialized".   
2027

N
NEEN 已提交
2028 2029 2030 2031
However, due to invalid initialization, the defect of placing "UseData" before "GetData" cannot be easily found.

Therefore, simple code should be written to initialize variables or memory blocks as required.

G
Gloria 已提交
2032
The C99 does not limit the definition position of local variables before the first statement in a function. That is, a variable can now be defined close to a variable.   
2033

N
NEEN 已提交
2034
This concise approach not only limits the scope of the variable scope, but also solves the problem of how to initialize the variable when it is defined.   
2035

N
NEEN 已提交
2036 2037
If this compilation environment is supported, you are advised to define local variables in this way.

W
wusongqing 已提交
2038
**Exceptions:**
2039

N
NEEN 已提交
2040 2041
**As 'Secure Coding Standard' required, pointers, resource variables, and boolean variables can be treated as exceptions of this rule.**

2042 2043 2044
### Rule 7.4 Do not use magic numbers.

The so-called magic numbers are the numbers that are unintelligible and difficult to understand.
N
NEEN 已提交
2045 2046 2047

The magic number is not a concept that can be defined literally. It varies depending on context and service knowledge.

2048 2049 2050 2051
For example, the number 12 varies in different contexts.  

`type = 12;` is not intelligible, but `month = year * 12;` can be understood. 

N
NEEN 已提交
2052 2053
The number 0 is sometimes seen as a magic number. For example, the `status = 0;` cannot truly express any status information.

2054 2055 2056 2057
Solution: 

Comments can be added for numbers that are used only once. 

N
NEEN 已提交
2058 2059
For numbers that are used multiple times, macro or const variables must be defined and self-commented with symbolic naming.

2060 2061 2062 2063
The following cases are forbidden: 

The name is not used to explain the meaning of a number, for example, `#define ZERO 0`. 

N
NEEN 已提交
2064 2065
The value is limited by the name, for example, `#define XX_TIMER_INTERVAL_300MS 300`.

2066
# 8 Programming Practice
N
NEEN 已提交
2067

2068
## Expressions
N
NEEN 已提交
2069

2070 2071 2072
### Rec 8.1 When comparing expressions, follow the principle that the left side tends to change and the right side tends to remain unchanged.

When a variable is compared with a constant, placing the constant on the left, for example, `if (MAX == v)` does not read naturally, and `if (MAX > v)` is more difficult to understand.  
N
NEEN 已提交
2073 2074 2075 2076 2077 2078 2079 2080 2081 2082

The constant should be placed on the right according to the normal reading order and habit. The expression is written as follows:

```c
if (v == MAX) ...
if (v < MAX) ...
```

There are special cases: for example, the expression `if (MIN < v && v < MAX)` is used to check for a range. This first constant should be placed on the left.

G
Gloria 已提交
2083
You do not need to worry about accidentally writing '==' as '=' because a compilation alarm will be generated for `if (v = MAX)` and an error will be reported by other static check tools. Use these tools to solve such writing errors and ensure that code is readable.
N
NEEN 已提交
2084

2085
### Do not reference a variable again in an expression containing an increment (++) or decrement (--) operator.
N
NEEN 已提交
2086

W
wusongqing 已提交
2087
In an expression containing a variable increment or decrement operator, if the variable is referenced again, the result is not explicitly defined in the C standard, which may vary between compilers or different compiler versions. 
2088

N
NEEN 已提交
2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118
For better portability, you should not make any assumptions about the operation sequence not defined in any standards.

Note that this problem cannot be solved by using parentheses because it is not a problem of priority.

Example:

```c
x = b[i] + i++; // Bad: b[i] operation and i++, the order is not clear.
```

The correct way is to add a separate line of increment or decrement:

```c
x = b[i] + i;
i++;            // Good: Single line.
```

Function parameter:

```c
Func(i++, i);   // Bad: When passing the second parameter, it is not sure whether the increment operation has occurred.
```

The correct way:

```c
i++;            // Good: Single line.
x = Func(i, i);
```

2119
### Rec 8.2 Use parentheses to specify the sequence of expressions, instead of using the default priority.
N
NEEN 已提交
2120 2121

Parentheses can be used to better emphasize the purpose of used operators. This will prevent program errors due to the inconsistency between default priority and the intended design.   
2122

N
NEEN 已提交
2123 2124 2125 2126 2127 2128 2129 2130
However, too many parentheses muddy the code, reducing readability. Use them moderately.

Parentheses are recommended when expressions contain operators that are not commonly used and are confusing, such as bitwise operators.

```c
c = (a & 0xFF) + b;     /* Parentheses are required while using bit operators. */
```

2131
## Statements
N
NEEN 已提交
2132

2133
### Rule 8.2 Provide a 'default' branch for the `switch` statement.
N
NEEN 已提交
2134 2135 2136

In most cases, the 'default' branch exists in the switch statement to ensure that there is a default processing action when the case tag is missing.

W
wusongqing 已提交
2137
Exceptions:
2138 2139 2140

If the switch condition variable is of the enum type and the case branches cover all values, then the default branch is redundant.  

N
NEEN 已提交
2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160
A modern compiler can check whether the case branch of some enumerated values is missing in the switch statement. A warning will be displayed.

```c
enum Color {
    RED,
    BLUE
};

// The switch condition variable is an enumerated value. Therefore, you do not need to add the 'default' processing branch.
switch (color) {
    case RED:
        DoRedThing();
        break;
    case BLUE:
        DoBlueThing();
        ... 
        break;
}
```

2161
### Rec 8.3 Exercise caution when using the `goto` statement.
N
NEEN 已提交
2162

W
wusongqing 已提交
2163
The `goto` statement destroys the program. Avoid using it if possible. You can only jump to statements following the `goto` statement, and only within the one function.
N
NEEN 已提交
2164

W
wusongqing 已提交
2165
The `goto` statement is used to implement function return to a single point within a function.
2166

N
NEEN 已提交
2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210
If a function has a large number of identical logics that cannot be encapsulated, for example, repeated file execution, the processed part of code after the file operation failure (for example, closing the file handle and releasing memory that is dynamically applied for) is usually placed in the last part of the function body. And the goto statement is placed right before these. In this way, the code becomes clear and concise. It can also be encapsulated in functions or macros, but doing so makes code less straightforward.

Example:

```c
// Good: Use a goto statement to implement function return at a single point.
int SomeInitFunc(void)
{
    void *p1;
    void *p2 = NULL;
    void *p3 = NULL;

    p1 = malloc(MEM_LEN);
    if (p1 == NULL) {
        goto EXIT;
    }

    p2 = malloc(MEM_LEN);
    if (p2 == NULL) {
        goto EXIT;
    }

    p3 = malloc(MEM_LEN);
    if (p3 == NULL) {
        goto EXIT;
    }

    DoSomething(p1, p2, p3);
    return 0;   // OK.

EXIT:
    if (p3 != NULL) {
        free(p3);
    }
    if (p2 != NULL) {
        free(p2);
    }
    if (p1 != NULL) {
        free(p1);
    }
    return -1;  // Failed!
}
```

2211
## Type Conversion
N
NEEN 已提交
2212

2213
### Rec 8.4 Minimize unnecessary type conversion and forced conversion.
N
NEEN 已提交
2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224

When the data type is forcibly changed, the meaning of the data and the value after conversion may change. If details are not considered, potential risks may be generated.

In the following assignment, most compilers do not generate warnings, but the values are slightly changed.

```c
char ch;
unsigned short int exam;

ch = -1;
exam = ch; // Bad: Compilers does not generate any warnings. In this case, the value of exam is 0xFFFF.
W
wusongqing 已提交
2225
```