• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# C Coding Style Guide
2
3## Purpose
4
5Rules 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:
6
71. Understand the ISO standard of C.
82. Be familiar with the basic features of C.
93. Understand the standard library of C.
10
11## General Principles
12
13Code must meet the requirements for **readability**, **maintainability**, **security**, **reliability**, **testability**, **efficiency**, and **portability** while ensuring functionality correctness.
14
15## Conventions
16
17**Rule**: Conventions that must be followed during programming.
18
19**Rec**: Conventions that must be considered during programming.
20
21It is necessary to understand the reason for these conventions and try to comply with them, no matter if they are rules or recommendations.
22
23## Exceptions
24
25The only acceptable exceptions are those that do not violate the general principles and provide appropriate reasons for their existence.
26
27Try to avoid exceptions because they affect the code consistency. Exceptions to 'Rules' should be very rare.
28
29The style consistency principle is preferred in the following case:
30
31**When you modify open-source or third-party code, comply with their respective code specifications.**
32
33# 1 Naming
34
35Names include file, function, variable, type, and macro names.
36
37Naming is considered the most difficult and important thing in software development.
38
39The name of an identifier must be clear, well defined, easy to understand, and accounting for reading habits.
40
41The unified naming style is the most direct expression of the consistency principle.
42
43## General Conventions
44
45**CamelCase**
46
47CamelCase 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
49There are two conventions: **UpperCamelCase and lowerCamelCase**.
50
51**Unix\_like**
52
53Unix\_like is also known as the snake style. In the Unix\_like style, words contain only lowercase letters and are separated by underscores (\_).
54
55Example: 'test_result'
56
57### Rule 1.1 Name identifiers in the CamelCase style.
58
59| Type| Naming Style|
60|----------|----------|
61| Function, struct, enum, union| UpperCamelCase|
62| Variable, function parameter, macro parameter, struct body, union member| lowerCamelCase|
63| Macro, constant, enumerated value, goto tag| All capitalized, separated by underscores (\_)|
64
65Note:
66
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
69**Variable** indicates the variables excluding those defined in **Constant**. These variables use the lowerCamelCase style.
70
71Unix\_like can be used for Linux or Unix friendly code.
72
73For code that is using the Unix\_like style, you can continue using this style.
74
75The same naming style must be used for the same function, struct, or union.
76
77### Rec 1.1 Use more accurate names for identifiers with a large scope.
78
79Different from C++, C does not have namespace or class. Therefore, the names of identifiers in the global scope must not conflict with each other.
80
81Names of global functions, global variables, macros, types, and enums must be accurately described and unique in the global scope.
82
83Example:
84
85```c
86int GetCount(void);                 // Bad: inaccurate description
87int GetActiveConnectCount(void);    // Good
88```
89
90For purposes of accurate naming, a module prefix can be added if necessary.
91
92The module prefix and the naming body can be connected by following the CamelCase style.
93
94Example:
95
96```c
97int PrefixFuncName(void);   // OK: CamelCase, a prefix in the content, but not in the format
98
99enum XxxMyEnum {            // OK
100    ...
101};
102```
103
104## File Naming
105
106### Rec 1.2 Use lowercase file names.
107
108Only lowercase letters, numbers, and underscores (\_) are allowed in file names.
109
110File names should be as short, accurate, and unambiguous as possible.
111
112The 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).
113
114Good example:
115
116`dhcp_user_log.c`
117
118Bad examples:
119
120`dhcp_user-log.c`: It is not recommended that you separate words with the hyphen (-).
121`dhcpuserlog.c`: The words are not separated, causing poor readability.
122
123## Function Naming
124
125Functions are named in the UpperCamelCase style.
126
127### Rec 1.3 Name functions to comply with reading habits.
128
129The "verb + object" structure can be used for action related function names. Example:
130
131```c
132AddTableEntry() // OK
133DeleteUser()    // OK
134GetUserInfo()   // OK
135```
136
137An adjective or a prefix "is" can be used in a function returning a Boolean value. Example:
138
139```c
140DataReady()     // OK
141IsRunning()     // OK
142JobDone()       // OK
143```
144
145Data or Getter function:
146
147```c
148TotalCount()    // OK
149GetTotalCount() // OK
150```
151
152## Variable Naming
153
154Variables 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.
155
156### Rule 1.2 Add the 'g_' prefix to global variables, but not to static variables in a function.
157
158Global 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
160Global 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.
161
162```c
163int g_activeConnectCount;
164
165void Func(void)
166{
167    static int pktCount = 0;
168    ...
169}
170```
171
172Notes: Constants are also global variables in essence. However, if constants are named using uppercase letters separated by underscores (\_), the current rule does not apply.
173
174### Rec 1.4 Keep local variables short and to the point.
175
176The name of a local variable should be short on the premise that meanings can be expressed through context.
177
178Example:
179
180```c
181int Func(...)
182{
183    enum PowerBoardStatus powerBoardStatusOfSlot; // Not good: Long redundant local variable
184    powerBoardStatusOfSlot = GetPowerBoardStatus(slot);
185    if (powerBoardStatusOfSlot == POWER_OFF) {
186        ...
187    }
188    ...
189}
190```
191
192Better writing style:
193
194```c
195int Func(...)
196{
197    enum PowerBoardStatus status;   // Good: The status can be clearly expressed in context.
198    status = GetPowerBoardStatus(slot);
199    if (status == POWER_OFF) {
200        ...
201    }
202    ...
203}
204```
205
206Similarly, "tmp" can be used to address any type of temporary variable.
207
208A 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.
209
210```c
211int i;
212...
213for (i = 0; i < COUNTER_RANGE; i++) {
214    ...
215}
216```
217
218Or, variables in simple math functions:
219
220```c
221int Mul(int a, int b)
222{
223	return a * b;
224}
225```
226
227## Type Naming
228
229Types are named in the UpperCamelCase style.
230
231The type can be a struct, a union, or an enum.
232
233Example:
234
235```c
236struct MsgHead {
237    enum MsgType type;
238    int msgLen;
239    char *msgBuf;
240};
241
242union Packet {
243    struct SendPacket send;
244    struct RecvPacket recv;
245};
246
247enum BaseColor {
248    RED,    // Note: The enum is in the UpperCamelCase style whereas the enumerated values adopt the macro naming style.
249    GREEN,
250    BLUE
251};
252
253typedef int (*NodeCmpFunc)(struct Node *a, struct Node *b);
254```
255
256When you use `typedef` to set an alias for a struct, a union, or an enum, try to use the anonymous type.
257If you need self-nesting pointers, you can add a 'tag' prefix or an underscore suffix.
258
259```c
260typedef struct {    // Good: The anonymous struct is used because self-nesting is not required.
261    int a;
262    int b;
263} MyType;           // The struct alias uses the UpperCamelCase style.
264```
265```c
266typedef struct tagNode {    // Good: Add the 'tag' prefix or use 'Node_'.
267    struct tagNode *prev;
268    struct tagNode *next;
269} Node;             // UpperCamelCase.
270```
271
272## Macro, Constant, and Enum Naming
273
274Use uppercase letters separated by underscores (\_) for macro names and enumerated values.
275
276You 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
278The constants here are defined as global const variables of the basic data type, enum type, or string type.
279
280Use uppercase letters separated by underscores (\_) for function-like macros.
281
282Exceptions:
283
2841. 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.
2852. 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.
2863. Macros for printing logs can be named in the same way as functions, using the UpperCamelCase style.
287Note: Function-like macros named in the UpperCamelCase style must be marked as macros in the API description.
288
289Macro example:
290
291```c
292#define PI 3.14
293#define MAX(a, b)   (((a) < (b)) ? (b) : (a))
294```
295
296```c
297#ifdef SOME_DEFINE
298void Bar(int);
299#define Foo(a) Bar(a)   // The function-like macro is named in the same way as a function.
300#else
301void Foo(int);
302#endif
303```
304
305Constant example:
306
307```c
308const int VERSION = 200;    // OK.
309
310const enum Color DEFAULT_COLOR = BLUE; // OK
311
312const char PATH_SEP = '/';  // OK
313
314const char * const GREETINGS = "Hello, World!"; // OK
315```
316
317Non-constant example:
318
319```c
320// A struct that does not meet the definition of constants
321const struct MyType g_myData = { ... };     // OK: Name it in lowerCamelCase style.
322
323// An array that does not meet the definition of constants
324const int g_xxxBaseValue[4] = { 1, 2, 4, 8 };   // OK: Name it in lowerCamelCase style.
325
326int Foo(...)
327{
328    // A local const variable that does not meet the definition of constants
329    const int bufSize = 100;    // OK: Name it in lowerCamelCase style.
330    ...
331}
332```
333
334Enum example:
335
336```c
337// Note: The enum type name is in the UpperCamelCase style, whereas the enumerated value is in uppercase letters separated by underscores (\_).
338enum BaseColor {
339    RED,
340    GREEN,
341    BLUE
342};
343```
344
345### Rec 1.5 Avoid temporary variables in function-like macros from polluting external scopes.
346
347**If possible, use a function instead of a function-like macro. Define a function-like macro only when necessary.**
348
349When 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:
350```c
351#define SWAP_INT(a, b) do { \
352    int tmp__ = a; \
353    a = b; \
354    b = tmp__; \
355} while (0)
356```
357
358# 2 Formatting
359
360## Line Length
361
362### Rule 2.1 Include 120 characters or less in each line.
363
364A longer line makes it more difficult for reading.
365
366To 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
368Unless a long line is necessary to maintain readability and present complete information, steer your document clear of long lines.
369
370Even on a high-resolution monitor, a long line increases the difficulty of reading. Strive for clearness and conciseness.
371
372Exceptions:
373
374- For code lines or comments, the use of the line feed causes content truncation and increases the search difficulty (grep).
375- The #include and #error statements are allowed to exceed the line length requirement. However, you should try to avoid this.
376
377Example:
378
379```c
380#ifndef XXX_YYY_ZZZ
381#error Header aaaa/bbbb/cccc/abc.h must only be included after xxxx/yyyy/zzzz/xyz.h
382#endif
383```
384
385## Indentation
386
387### Rule 2.2 Use spaces to indent and indent four spaces at a time.
388
389Only spaces can be used for indentation. Four spaces are indented each time. Do not use the Tab character to indent.
390
391Currently, 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.
392
393## Braces
394
395### Rule 2.3 Use the K\&R indentation style.
396
397**K\&R style**
398
399While 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.
400
401The 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.
402
403Example:
404
405```c
406struct MyType {     // Good: The left brace is placed at the end of the line along with the statement, and one space is used for indentation.
407    ...
408};                  // Good: The right brace is followed by the semicolon.
409
410int Foo(int a)
411{                   // Good: The left brace of the function starts a new line, and nothing else is placed on the line.
412    if (...) {
413        ...
414    } else {        // Good: The right brace is followed by the `else` statement.
415        ...
416    }               // Good: The right brace takes a single line.
417}
418```
419
420## Function Declaration and Definition
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.
423
424When a function is declared and defined, the return value type of the function should be in the same line as the function name.
425
426When the function parameter list is wrapped, it should be aligned appropriately.
427The left parenthesis of a parameter list is always in the same line as the function name. The right parenthesis always follows the last parameter.
428
429Example:
430
431```c
432ReturnType FunctionName(ArgType paramName1, ArgType paramName2)   // Good: All in one line
433{
434    ...
435}
436
437ReturnType VeryVeryVeryLongFunctionName(ArgType paramName1,     // Each added parameter starts on a new line because the line length limit is exceeded.
438                                        ArgType paramName2,     // Good: Aligned with the previous line
439                                        ArgType paramName3)
440{
441    ...
442}
443
444ReturnType LongFunctionName(ArgType paramName1, ArgType paramName2, // Parameters are wrapped because the line length limit is exceeded.
445    ArgType paramName3, ArgType paramName4, ArgType paramName5)     // Good: 4 spaces are used for indentation.
446{
447    ...
448}
449
450ReturnType ReallyReallyReallyReallyLongFunctionName(            // The line length cannot accommodate even the first parameter, and a line break is required.
451    ArgType paramName1, ArgType paramName2, ArgType paramName3) // Good: 4 spaces are used for indentation.
452{
453    ...
454}
455```
456
457## Function Calls
458
459### Rule 2.5 Align the parameter list appropriately if it needs to be wrapped.
460
461In a function call, if the function parameter list is wrapped, it should be aligned appropriately.
462
463The left parenthesis is always followed by a function name, and the right parenthesis always follows the last parameter.
464
465Example:
466
467```c
468ReturnType result = FunctionName(paramName1, paramName2);   // Good: Function parameters are placed in one line.
469
470ReturnType result = FunctionName(paramName1,
471                                 paramName2,                // Good: Aligned with the above parameters
472                                 paramName3);
473
474ReturnType result = FunctionName(paramName1, paramName2,
475    paramName3, paramName4, paramName5);                    // Good: 4 spaces are used for indentation.
476
477ReturnType result = VeryVeryVeryLongFunctionName(           // The line length cannot accommodate the first parameter, and therefore line feed is used.
478    paramName1, paramName2, paramName3);                    // 4 spaces are used for indentation.
479```
480
481If 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.
482
483```c
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.
485int result = DealWithStructureLikeParams(left.x, left.y,     // Indicates a group of parameters.
486                                         right.x, right.y);  // Indicates another group of related parameters.
487```
488
489## Conditional Statements
490
491### Rule 2.6 Use braces for conditional statements.
492
493Use braces to enclose conditional statements, even if there is only one statement.
494
495Reason:
496
497- Logic is intuitive and easy to read.
498- It is not easy to make mistakes when adding new code to the existing conditional statement.
499- Function-like macros without braces are used in conditional statements, can be error prone if braces do not surround the conditional statement.
500
501```c
502if (objectIsNotExist) {         // Good: Braces are added to a single-line conditional statement.
503    return CreateNewObject();
504}
505```
506
507### Rule 2.7 Do not place `if`, `else`, and `else if` in the same line.
508
509In a conditional statement, branches, if any, should be written in different lines.
510
511Good example:
512
513```c
514if (someConditions) {
515    ...
516} else {    // Good: The `else` statement is in a different line of `if`.
517    ...
518}
519```
520
521Bad example:
522
523```c
524if (someConditions) { ... } else { ... } // Bad: They are in the same line.
525```
526
527## Loops
528
529### Rule 2.8 Use braces for loop statements.
530
531Use braces to enclose the `for` and `while` statements, even if there is only one loop.
532
533```c
534for (int i = 0; i < someRange; i++) {   // Good: Braces are used.
535    DoSomething();
536}
537```
538
539```c
540while (condition) { }   // Good: The entire loop body is empty. And braces are used.
541```
542
543```c
544while (condition) {
545    continue;           // Good: The continue keyword highlights the end of the empty loop. And braces are used.
546}
547```
548
549Bad example:
550
551```c
552for (int i = 0; i < someRange; i++)
553    DoSomething();      // Bad: Braces should be added.
554```
555
556```c
557while (condition);      // Bad: The semicolon may be treated as part of the `while` statement.
558```
559
560## `switch` Statements
561
562### Rule 2.9 Indent the `case` or `default` statement in a `switch` statement block.
563
564Use the following indentation style for the `switch` statement:
565
566```c
567switch (var) {
568    case 0:             // Good: Indented
569        DoSomething1(); // Good: Indented
570        break;
571    case 1: {           // Good: Braces are added.
572        DoSomething2();
573        break;
574    }
575    default:
576        break;
577}
578```
579
580```c
581switch (var) {
582case 0:                 // Bad: 'case' not indented
583    DoSomething();
584    break;
585default:                // Bad: 'default' not indented
586    break;
587}
588```
589
590## Expressions
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.
593
594A 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.
595
596Example:
597
598```c
599// Assume that the first line does not meet the line length requirement.
600if ((currentValue > MIN) &&  // Good: The Boolean operator is placed at the end of the line.
601    (currentValue < MAX)) {
602    DoSomething();
603    ...
604}
605
606int result = reallyReallyLongVariableName1 +    // Good: The plus sign is placed at the end of the line.
607             reallyReallyLongVariableName2;
608```
609
610After an expression is wrapped, ensure that the lines are properly aligned or indented by 4 spaces. Example:
611
612```c
613int sum = longVariableName1 + longVariableName2 + longVariableName3 +
614    longVariableName4 + longVariableName5 + longVariableName6;         // OK: indented with 4 spaces
615
616int sum = longVariableName1 + longVariableName2 + longVariableName3 +
617          longVariableName4 + longVariableName5 + longVariableName6;   // OK: aligned
618```
619
620## Variable Assignment
621
622### Rule 2.10 Do not write multiple variable definitions or assignment statements in one line.
623
624It is recommended that each line contain only one variable initialization statement, which is easier to read and understand.
625
626```c
627int maxCount = 10;
628bool isCompleted = false;
629```
630
631Bad example:
632
633```c
634int maxCount = 10; bool isCompleted = false; // Bad: Multiple initialization statements are placed in one line.
635int x, y = 0;  // Bad: Multiple variable definitions are placed in one line.Each definition occupies one line.
636
637int pointX;
638int pointY;
639...
640pointX = 1; pointY = 2;  // Bad: Multiple variable assignment statements are placed in one line.
641```
642
643Exceptions:
644If multiple variable definitions have strong correlation and do not need to be initialized, you can define the variables in a line for code compactness.
645
646```c
647int i, j;  // Good: Multiple variable definitions that do not need to be initialized are written in one line.
648for (i = 0; i < row; i++) {
649    for (j = 0; j < col; j++) {
650        ...
651    }
652}
653```
654
655## Initialization
656
657Initialization is applicable to structs, unions, and arrays.
658
659### Rule 2.11 Use indentation or make a reasonable alignment for a new line.
660
661For the struct or array initialization, use 4 spaces for indentation if a line break is made.
662
663From better readability, make a reasonable alignment.
664
665```c
666// Good: No line break for a short line.
667int arr[4] = { 1, 2, 3, 4 };
668
669// Good: A line break makes better readability.
670const int rank[] = {
671    16, 16, 16, 16, 32, 32, 32, 32,
672    64, 64, 64, 64, 32, 32, 32, 32
673};
674```
675
676For complex data, the initialization should be clear and compact.
677Refer to the following format:
678
679```c
680int a[][4] = {
681    { 1, 2, 3, 4 }, { 2, 2, 3, 4 }, // OK
682    { 3, 2, 3, 4 }, { 4, 2, 3, 4 }
683};
684
685int b[][8] = {
686    { 1, 2, 3, 4, 5, 6, 7, 8 },     // OK
687    { 2, 2, 3, 4, 5, 6, 7, 8 }
688};
689```
690
691```c
692int c[][8] = {
693    {
694        1, 2, 3, 4, 5, 6, 7, 8      // OK
695    }, {
696        2, 2, 3, 4, 5, 6, 7, 8
697    }
698};
699```
700
701Note:
702
703- If the left brace is placed at the end of the line, the corresponding right brace should be placed into a new line.
704- If the left brace is followed by the content, the corresponding right brace should also follow the content.
705
706### Rule 2.12 Initialize each member in a separate line during struct and union member initialization.
707
708The 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.
709
710```c
711struct Date {
712    int year;
713    int month;
714    int day;
715};
716
717struct Date date = {    // Good: When the designated initializer is used, each member is initialized in a separate line.
718    .year   = 2000,
719    .month  = 1,
720    .day    = 1
721};
722```
723
724## Pointers
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.
727
728When 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.
729
730```c
731int *p1;    // OK
732int* p2;    // OK
733
734int*p3;     // Bad: No space
735int * p4;   // Bad: Space on both sides
736```
737
738Choose a style and stay consistent.
739
740If you use the asterisk to follow the type, do not declare multiple variables with pointers in a line.
741
742```c
743int* a, b;  // Bad: b may be treated as a pointer.
744```
745
746Do not use the asterisk followed by the variable name if this style is not suitable in all cases.
747Keep style consistency first.
748
749```c
750char * const VERSION = "V100";      // OK
751int Foo(const char * restrict p);   // OK
752```
753
754Do not use the asterisk to follow the `const` or `restrict` keywords.
755
756## Compilation Preprocessing
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.
759
760The 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
762Try 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.
763
764## Whitespace
765
766### Rule 2.14 Use horizontal whitespaces to highlight keywords and important information, and avoid unnecessary whitespaces.
767
768Horizontal 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:
769
770- Add spaces after keywords such as `if`, `switch`, `case`, `do`, `while`, and `for`.
771- Do not add spaces after the left parenthesis or before the right parenthesis.
772- Add a space before and after each binary operator (= + - \< > \* / % \| \& \^ \<= >= == !=).
773- Do not add a space after any unary operator (\& \* + - ~!).
774- Add a space before and after each ternary operator (? :).
775- Add spaces before and after the colon of bit field description.
776- Do not add spaces between ++/-- and variables.
777- Do not add spaces before and after the struct member operator (. ->).
778- Adding or not adding spaces inside the brace must be consistent.
779- 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.
780- Do not add spaces between the parentheses of the function parameter list and the function name.
781- Do not add spaces between the parenthesis of the type cast and the object being converted.
782- Do not add spaces between the square bracket of the array and the array name.
783- Spaces at the end of the line can be omitted.
784
785For spaces inside the braces, the following **recommendations** are available:
786
787- It is recommended that spaces be added after the left brace and before the right brace.
788- For an empty constant or a constant with a single identifier or a single word, spaces are not required, for example, '{}', '{0}', '{NULL}', '{"hi"}'.
789- 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.
790
791In normal cases:
792
793```c
794int i = 0;                  // Good: When the variable is initialized, there should be spaces before and after the =. Do not leave a space before the semicolon.
795int buf[BUF_SIZE] = {0};    // Good: For array initialization, spaces in curly braces are optional.
796int arr[] = { 10, 20 };     // Good: A space is added before and after the brace.
797```
798
799Function definition and call:
800
801```c
802int result = Foo(arg1,arg2);
803                      ^         // Bad: There is no space after the comma.
804
805int result = Foo( arg1, arg2 );
806                 ^          ^   // Bad: No space should be added to either side in the parentheses.
807```
808
809Pointer and address-of operator:
810
811```c
812x = *p;     // Good: There is no space between the operator (*) and the pointer p.
813p = &x;     // Good: There is no space between the operator (&) and the variable x.
814x = r.y;    // Good: When a member variable is accessed through the operator (.), no space is added.
815x = r->y;   // Good: When a member variable is accessed through the operator (->), no space is added.
816```
817
818Operator:
819
820```c
821x = 0;    // Good: There is a space before and after the assignment operator (=).
822x = -5;   // Good: There is no space between the minus sign (-) and the number.
823++++x; // Good: There is no space between ++/-- and the variable.
824x--;
825
826if (x && !y)        // Good: There is a space before and after the Boolean operator, and there is no space between the operator (!) and variable.
827v = w * x + y / z;  // Good: There is a space before and after binary operators.
828v = w * (x + z);    // Good: There is no space before and after the expression in the parentheses.
829```
830
831Loops and conditional statements:
832
833```c
834if (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.
835    ...
836} else {            // Good: A space is added between the `else` keyword and the curly brace.
837    ...
838}
839
840while (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.
841
842for (int i = 0; i < someRange; ++i) {  // Good: A space is added between the `for` keyword and the parenthesis, and after the semicolons (;).
843    ...
844}
845
846switch (var) {  // Good: A space is added after the `switch` keyword.
847    case 0:     // Good: No space is added between the `case` conditional statement and the colon (:).
848        ...
849        break;
850    ...
851    default:
852        ...
853        break;
854}
855```
856
857Note: The current IDE and code editor can be set to delete spaces at the end of a line. Configure your editor correctly.
858
859### Rec 2.3 Arrange blank lines reasonably to keep the code compact.
860
861Reduce unnecessary blank lines so that more code can be displayed for easy reading. The following rules are recommended:
862
863- Make a reasonable arrangement of blank lines according to the degree of relevance of neighboring content.
864- Do not put two or more consecutive blank lines inside a function, a type definition, a macro, or an initialization expression.
865- Do not use **three** or more consecutive blank lines.
866- Do not add blank lines at the start and end of a code block defined by braces.
867
868```c
869ret = DoSomething();
870
871if (ret != OK) {    // Bad: Return value judgment should follow the function call.
872    return -1;
873}
874```
875
876```c
877int Foo(void)
878{
879    ...
880}
881
882
883
884int Bar(void)       // Bad: Use no more than two continuous blank lines.
885{
886    ...
887}
888```
889
890```c
891int Foo(void)
892{
893
894    DoSomething();  // Bad: The blank lines above and below are unnecessary.
895    ...
896
897}
898```
899
900# 3 Comments
901
902Generally, clear architecture and good symbol naming are recommended to improve code readability, and comments are provided only when necessary.
903
904Comments help readers quickly understand code. Therefore, **comments should be provided when necessary** for the sake of readers.
905
906The comments must be concise, clear, and unambiguous, ensuring that the information is complete and not redundant.
907
908**Comments are as important as code.**
909
910When 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
912When 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.
913
914Comment code in fluent **English**.
915
916Comments must be added in the following scenarios (including but not limited to the listed scenarios):
9171. Functions in the external interface header file provided by the module
9182. Global variables being defined
9193. Core algorithms
9204. A function that contains more than 50 lines
921
922## Comment Style
923
924In C code, both `/*` `*/` and `//` can be used.
925
926Comments can be classified into different types depending on the purpose and position, such as file header comments, function header comments, and general comments.
927
928Comments of the same type must keep a consistent style.
929
930Note: 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.
931
932## File Header Comments
933
934### Rule 3.1 Include the copyright license in the file header comments.
935
936/\*
937
938* Copyright (c) 2020 Huawei Device Co., Ltd.
939* Licensed under the Apache License, Version 2.0 (the "License");
940* you may not use this file except in compliance with the License.
941* You may obtain a copy of the License at
942*
943* http://www.apache.org/licenses/LICENSE-2.0
944*
945* Unless required by applicable law or agreed to in writing, software
946* distributed under the License is distributed on an "AS IS" BASIS,
947* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
948* See the License for the specific language governing permissions and
949* limitations under the License. \*/
950
951## Function Header Comments
952
953### Rule 3.2 Do not use empty function header comments with no content.
954
955Not all functions need function header comments.
956
957Function header comments must be added for any information that cannot be expressed just with function prototype.
958
959Function header comments are placed above the function declaration or definition.
960
961Select and use one of the following styles:
962
963**Use '//' to start the function header.**
964
965```c
966// Single-line function header
967int Func1(void);
968
969// Multi-line function header
970// Second line
971int Func2(void);
972```
973
974**Use '/\*' '\*/' to start the function header.**
975
976```c
977/* Single-line function header */
978int Func1(void);
979
980/*
981 * Single-line or multi-line function header
982 * Second line
983 */
984int Func2(void);
985```
986
987Use function names to describe functions, and only add function header comments if necessary.
988
989Do not write useless or redundant function headers. Do not write empty function headers with no content.
990
991The following content is **optional** in the function header comment: function description, return value, performance constraint, usage, memory convention, algorithm implementation, and reentering requirement.
992
993In the function interface declaration in the external header file of the module, the function header comment should clearly describe important and useful information.
994
995Example:
996
997```c
998/*
999 * The number of written bytes is returned. If -1 is returned, the write operation fails.
1000 * Note that the memory buffer is released by the caller.
1001 */
1002int WriteString(char *buf, int len);
1003```
1004
1005Bad example:
1006
1007```c
1008/*
1009 * Function name: WriteString
1010 * Function: Write a character string.
1011 * Parameter:
1012 * Return value:
1013 */
1014int WriteString(char *buf, int len);
1015```
1016
1017Problems in the preceding example are as follows:
1018
1019- The 'Parameter' and 'Return value' headings have no content.
1020- The function name has redundant information.
1021- It does not clearly state the party that should release the buffer.
1022
1023## Code Comments
1024
1025### Rule 3.3 Place code comments above or to the right of the code.
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.
1028
1029Comments placed above code should be indented to the same level as the code.
1030
1031Select and use one of the following styles:
1032
1033**Use '//' to start the comment.**
1034
1035```c
1036// Single-line comment
1037DoSomething();
1038
1039// Multi-line comment
1040// Second line
1041DoSomething();
1042```
1043
1044**Use '/\*' '\*/' to start the comment.**
1045
1046```c
1047/* Single-line comment */
1048DoSomething();
1049
1050/*
1051 * Single-/Multi-line comment
1052 * Second line
1053 */
1054DoSomething();
1055```
1056
1057Leave at least one space between the code and the comment on the right. No more than four spaces are recommended.
1058
1059
1060You can use the extended Tab key to indent 1-4 spaces.
1061
1062Select and use one of the following styles:
1063
1064```c
1065int foo = 100;  // Comment on the right
1066int bar = 200;  /* Comment on the right */
1067```
1068
1069It is more appealing sometimes when the comment is placed to the right of code and the comments and code are aligned vertically.
1070
1071After the alignment, ensure that the comment is 1–4 spaces separated from the closest code line on the left.
1072
1073
1074Example:
1075
1076```c
1077#define A_CONST 100         /* Related comments of the same type can be aligned vertically. */
1078#define ANOTHER_CONST 200   /* Leave spaces after code to align comments vertically. */
1079```
1080
1081If the comment on the right exceeds the permitted line length, the comment can be placed above the code.
1082
1083### Rule 3.5 Delete unused code segments. Do not comment them out.
1084
1085Code that is commented out cannot be maintained. If you attempt to restore the code, it is very likely to introduce ignorable defects.
1086
1087The correct method is to delete unnecessary code. If necessary, consider porting or rewriting the code.
1088
1089Here, 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.
1090
1091### Rec 3.1 Provide comments if `break` or `return` is not added to the end of the `case` statement block (fall-through).
1092
1093Sometimes, 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".
1094
1095In this case, add comments for the "fall-through" to clearly express your intention, or at least explicitly specify the "fall-through".
1096
1097For example, to explicitly specify the "fall-through":
1098
1099```c
1100switch (var) {
1101    case 0:
1102        DoSomething();
1103        /* fall-through */
1104    case 1:
1105        DoSomeOtherThing();
1106        ...
1107        break;
1108    default:
1109        DoNothing();
1110        break;
1111}
1112```
1113
1114If the `case` statement is empty, no comment is required to explain the "fall-through".
1115
1116```c
1117switch (var) {
1118    case 0:
1119    case 1:
1120        DoSomething();
1121        break;
1122    default:
1123        DoNothing();
1124        break;
1125}
1126```
1127
1128# 4 Header Files
1129
1130**For the C programming language, the design of the header file reflects most of the system design.**
1131
1132The correct use of the header file makes code more readable, reduces file size, and speeds up compilation and build performance.
1133
1134The following programming specifications aim to help you properly plan header files.
1135
1136## Header File Responsibility
1137
1138A header file is an external interface of a module or file.
1139
1140The interface declaration for most functions (except inline functions) is suitable in the header file. Interface implementations are not allowed in the header file.
1141
1142Header responsibility should be simple. A complex header file will make dependencies complex and cause a long compilation time.
1143
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.
1145
1146Generally, 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.
1147If a .c file does not need to open any interface externally, it should not exist.
1148
1149Exceptions: the entry point of the program (for example, the file where the main function is located), unit test code, and dynamic library code.
1150
1151Example:
1152
1153Content of **foo.h**:
1154
1155```c
1156#ifndef FOO_H
1157#define FOO_H
1158
1159int Foo(void);  // Good: Declare an external interface in the header file.
1160
1161#endif
1162```
1163
1164Content of **foo.c**:
1165
1166```c
1167static void Bar(void);  // Good: The declaration of the internal function is placed in the header of the .c file, declaring its static scope.
1168
1169void Foo(void)
1170{
1171    Bar();
1172}
1173
1174static void Bar(void)
1175{
1176    // Do something;
1177}
1178```
1179
1180Internally used functions declarations, macros, enums, structs, and others should not be placed in header files.
1181
1182In 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.
1183
1184This style is not recommended. It is used only because the .c file is too large. You should consider splitting the .c file first.
1185In addition, if private definitions and declarations are placed in independent header files, they technically cannot avoid inclusion.
1186
1187This rule, in turn, is not necessarily correct. Example:
1188Some simple header files, such as the command ID definition header file, do not need to have the corresponding .c file.
1189
1190If a set of interface protocols has multiple instances and the interface is fixed, one .h file can have multiple .c files.
1191
1192### Rec 4.2 Use .h as the extension of the header file, rather than other unconventional extensions, for example, .inc.
1193
1194Some 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.
1195
1196However, 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).
1197
1198## Header File Dependency
1199
1200The header file contains a dependency, and the dependency should be stable.
1201
1202Generally, an unstable module depends on a stable module. When the unstable module changes, the build of the stable module is not affected.
1203
1204Dependency direction is as follows: Products depend on the platform, and the platform depends on the standard library.
1205
1206In 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.
1207
1208It is assumed that the interface is the most stable.
1209
1210### Rule 4.1 Forbid cyclic dependency of header files.
1211
1212Cyclic 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.
1213
1214For 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.
1215
1216The cyclic dependency of header files reflects an obviously unreasonable architecture design, which can be avoided through optimization.
1217
1218### Rule 4.2 Include the internal #include protection character (#define protection) in the header file.
1219
1220To prevent header files from being included multiple times, all header files should be protected by #define. Do not use #pragma once.
1221
1222When defining a protection character, comply with the following rules:
1223
1224- Use a unique name for the protection character in the format of subsystem\_component\_file.
1225- Do not place code or comments before or after the protected part, except for file header comments.
1226
1227Assume 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:
1228```c
1229#ifndef UTIL_TIMER_TIMER_H
1230#define UTIL_TIMER_TIMER_H
1231
1232...
1233
1234#endif // UTIL_TIMER_TIMER_H
1235```
1236
1237### Rule 4.3 Do not reference external function interfaces and variables by using declaration.
1238
1239You can use the interfaces provided by other modules or files only by using header files.
1240
1241Using external function interfaces and variables with an extern declaration may cause inconsistency between declarations and definitions when external interfaces are changed.
1242
1243In addition, this kind of implicit dependency may cause architecture corruption.
1244
1245Cases that do not comply with specifications:
1246
1247Content of **a.c**:
1248
1249```c
1250extern int Foo(void);   // Bad: Reference external functions by using the extern declaration.
1251void Bar(void)
1252{
1253    int i = Foo();  // Here, the external interface Foo is used.
1254    ...
1255}
1256```
1257
1258It should be changed to:
1259Content of **a.c**:
1260
1261```c
1262#include "b.h"      // Good: Use the interfaces provided by another .c file by including the header file.
1263void Bar(void)
1264{
1265    int i = Foo();
1266    ...
1267}
1268```
1269
1270Content of **b.h**:
1271
1272```c
1273int Foo(void);
1274```
1275
1276Content of **b.c**:
1277
1278```c
1279int Foo(void)
1280{
1281    // Do something
1282}
1283```
1284
1285In some scenarios, if internal functions need to be referenced with no intrusion to the code, the extern declaration mode can be used.
1286
1287Example:
1288
1289When performing unit testing on an internal function, you can use the extern declaration to reference the tested function.
1290
1291When a function needs to be stubbed or patched, the function can be declared using extern.
1292
1293### Rule 4.4 Do not include header files in extern "C".
1294
1295If 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.
1296
1297extern "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.
1298
1299Assume that there are two header files: **a.h** and **b.h**.
1300Content of **a.h**:
1301
1302```c
1303...
1304#ifdef __cplusplus
1305void Foo(int);
1306#define A(value) Foo(value)
1307#else
1308void A(int)
1309#endif
1310```
1311
1312Content of **b.h**:
1313
1314```c
1315...
1316#ifdef __cplusplus
1317extern "C" {
1318#endif
1319
1320#include "a.h"
1321void B(void);
1322
1323#ifdef __cplusplus
1324}
1325#endif
1326```
1327
1328When you use the C++ preprocessor to expand **b.h**, the following information is displayed:
1329
1330```c
1331extern "C" {
1332    void Foo(int);
1333    void B(void);
1334}
1335```
1336
1337In the **a.h** file, the **Foo** function is intended to be a C++ free function following the C++ specifications.
1338
1339However, in the **b.h** file, because `#include "a.h"` is placed inside `extern "C"`, the linking specification of the **Foo** function is changed incorrectly.
1340
1341Exceptions: 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"`.
1342
1343# 5 Functions
1344
1345Functions 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.
1346
1347Functions should be concise and short.
1348
1349One function completes only one thing.
1350
1351## Function Design
1352
1353The 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.
1354
1355### Rule 5.1 Avoid long functions and ensure that functions contain no more than 50 lines (excluding blank lines and comments).
1356
1357A function should be able to be displayed on one screen (fewer than 50 lines). It does only one thing and does it well.
1358
1359A long function usually means that it aims to implement complex functionalities or contains excess details.
1360
1361Exceptions:
1362
1363Considering the code's aggregation and functionality, some functions may exceed 50 lines, but only if the code is readable and concise.
1364
1365These exceptions should be minimal, such as specific algorithm processing.
1366
1367Even 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.
1368
1369It 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.
1370
1371### Rule 5.2 Avoid nesting a code block more than four times within a function.
1372
1373The 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
1375Each layer of nesting increases the difficulty in reading the code.
1376
1377Further functional decomposition should be done for better understanding.
1378
1379Using `guard clauses` can effectively reduce the nesting layers of the `if` statements. Example:
1380Three nesting layers are used originally:
1381
1382```c
1383int Foo(...)
1384{
1385    if (received) {
1386        type = GetMsgType(msg);
1387        if (type != UNKNOWN) {
1388            return DealMsg(...);
1389        }
1390    }
1391    return -1;
1392}
1393```
1394
1395Two nesting layers after code reconstruction using `guard clauses`:
1396
1397```c
1398int Foo(...)
1399{
1400    if (!received) {    // Good: Use the 'guardian statement'.
1401        return -1;
1402    }
1403
1404    type = GetMsgType(msg);
1405    if (type == UNKNOWN) {
1406        return -1;
1407    }
1408
1409    return DealMsg(..);
1410}
1411```
1412
1413Exceptions:
1414
1415Considering 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
1417These exceptions should be rare.
1418
1419### Rec 5.1 Process all returned error codes.
1420
1421A 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.
1422
1423Example:
1424
1425```c
1426char fileHead[128];
1427ReadFileHead(fileName, fileHead, sizeof(fileHead)); // Bad: The return value is not checked.
1428
1429DealWithFileHead(fileHead, sizeof(fileHead));       // The 'fileHead' is possibly invalid.
1430```
1431
1432The correct format is as follows:
1433
1434```c
1435char fileHead[128];
1436ret = ReadFileHead(fileName, fileHead, sizeof(fileHead));
1437if (ret != OK) {                // Good: Ensure that the 'fileHead' is written.
1438    return ERROR;
1439}
1440
1441DealWithFileHead(fileHead, sizeof(fileHead));       // Process the file header.
1442```
1443
1444If 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
1446Only if the caller of a function really doesn't need a return value, should you design the function to return `void`.
1447
1448## Function Parameters
1449
1450### Rec 5.2 Use the return value instead of the output parameter when designing a function.
1451
1452Using return values rather than output parameters improves readability and usually provides the same or better performance.
1453
1454Readability can be improved by naming functions such as GetXxx, FindXxx, IsXxx, OnXxx, or directly using a single noun, to directly return the corresponding object.
1455
1456Exceptions:
14571. When multiple values are returned, you can design an output parameter for the function.
14582. 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.
1459
1460### Rec 5.3 Define function parameters in the sequence of input, output, and input/output parameters.
1461
1462You are advised to define function parameters in the sequence of input, output, and input/output parameters.
1463
1464### Rule 5.3 Provide a release function if allocation of resources, such as memory, locks, and queues, is involved.
1465
1466Resources should be released from where they are applied for. If a function applies for resources, the module must provide resource functions.
1467
1468### Rec 5.4 Use strongly typed parameters. Do not use void\*.
1469
1470While 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.
1471
1472The advantage of this strongly typed style is to prevent evasive errors by catching errors at the compilation stage.
1473
1474Strong types help the compiler find more errors.Pay attention to the usage of the `FooListAddNode` function in the following code:
1475
1476```c
1477struct FooNode {
1478    struct List link;
1479    int foo;
1480};
1481
1482struct BarNode {
1483    struct List link;
1484    int bar;
1485}
1486
1487void FooListAddNode(void *node) // Bad: Here, the void * type is used to pass parameters.
1488{
1489    FooNode *foo = (FooNode *)node;
1490    ListAppend(&g_fooList, &foo->link);
1491}
1492
1493void MakeTheList(...)
1494{
1495    FooNode *foo;
1496    BarNode *bar;
1497    ...
1498
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.
1500}
1501
1502```
1503
1504The preceding problems may be difficult to expose and are more destructive than compiler errors.
1505If the parameter type of `FooListAddNode` is specified clearly, instead of with the `void *` type, the preceding problem can be detected during compilation.
1506
1507```c
1508void FooListAddNode(FooNode *foo)
1509{
1510    ListAppend(&g_fooList, &foo->link);
1511}
1512```
1513
1514Exceptions: For some generic interfaces, you can use the input parameter `void *` to pass different types of pointers.
1515
1516### Rec 5.5 It is the caller's responsibility to check the validity of internal function parameters of a module.
1517
1518Validity check must be performed on parameters passed from external modules to protect programs from being damaged by invalid input data.
1519
1520When 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.
1521
1522When the caller ensures the validity of any received data, this contractual programming makes logic simpler and code more readable.
1523
1524Example:
1525
1526```c
1527int SomeProc(...)
1528{
1529    int data;
1530
1531    bool dataOK = GetData(&data);       // Get data.
1532    if (!dataOK) {                      // Check the result of the previous step to ensure data validity.
1533        return -1;
1534    }
1535
1536    DealWithData(data);                 // Call the data processing function.
1537    ...
1538}
1539
1540void DealWithData(int data)
1541{
1542    if (data < MIN || data > MAX) {     // Bad: The caller has already ensured data validity.
1543        return;
1544    }
1545
1546    ...
1547}
1548```
1549
1550### Rec 5.5 Declare the pointer argument of a function as 'const' if it is not used to modify the pointed object.
1551
1552The const pointer argument, which restricts the function from modifying the object through the pointer, makes code stronger and safer.
1553
1554Example: In the example of the strncmp in the 7.21.4.4 of the C99 standard, the invariant parameter is declared as const.
1555
1556```c
1557int strncmp(const char *s1, const char *s2, size_t n); // Good: The invariant parameter is declared as const.
1558```
1559
1560Note: 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.
1561
1562### Rec 5.6 Include no more than 5 parameters in a function.
1563
1564If 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.
1565
1566The number of parameters in a function must not exceed 5. If the number of parameters exceeds 5, consider the following:
1567
1568- Check whether the function can be split.
1569- Check whether any related parameters can be combined and defined as a struct.
1570
1571## Inline Functions
1572
1573An 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).
1574
1575### Rec 5.7 Include no more than 10 lines in an inline function (excluding blank lines and comments).
1576
1577Defining 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.
1578
1579Vice versa, if the function body is large, inlining will cause expansion of the target code, especially when there are many call points.
1580
1581
1582It is recommended that inline functions be controlled to within **10** lines.
1583
1584Do 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.
1585
1586### Rule 5.3 Define inline functions that will be called by multiple source files in the header file.
1587
1588Inline functions are unfolded in compilation. Therefore, the inline function definition must be visible in each source file that calls this function.
1589
1590As 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.
1591
1592inline.h
1593
1594```c
1595inline int SomeInlineFunc(void);
1596```
1597
1598inline.c
1599
1600```c
1601inline int SomeInlineFunc(void)
1602{
1603    // Implementation code
1604}
1605```
1606
1607other.c
1608
1609```c
1610#include "inline.h"
1611int OtherFunc(void)
1612{
1613    int ret = SomeInlineFunc();
1614}
1615```
1616
1617Due 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
1619The inline function implementation in **gnu89** differs from that in the **C99** standard. For compatibility, you can declare the function as **static inline**.
1620
1621# 6 Macros
1622
1623## Function-like Macros
1624
1625A 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.
1626
1627```c
1628#define ASSERT(x) do { \
1629    if (!(x)) { \
1630        printk(KERN_EMERG "assertion failed %s: %d: %s\n", \
1631              __FILE__, __LINE__, #x); \
1632        BUG(); \
1633    } \
1634} while (0)
1635```
1636
1637### <a name="a6-1"></a>Rec 6.1 Use functions instead of function-like macros.
1638
1639Before 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.
1640
1641The disadvantages of the function-like macro are as follows:
1642
1643- 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- 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).
1645- 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.
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.
1647- Extensions of some macros can only be implemented by specific compilers in specific scenarios, such as `statement expression` of `gcc`, reducing the portability.
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.
1649- 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.
1650
1651<a name="macro_lack_of_type_check__example"></a>Example code of a function-like macro lacking type check:
1652
1653```c
1654#define MAX(a, b)   (((a) < (b)) ? (b) : (a))
1655
1656int Max(int a, int b)
1657{
1658    return (a < b) ? b : a;
1659}
1660
1661int TestMacro(void)
1662{
1663    unsigned int a = 1;
1664    int b = -1;
1665
1666    (void)printf("MACRO: max of a(%u) and b(%d) is %d\n", a, b, MAX(a, b));
1667    (void)printf("FUNC : max of a(%u) and b(%d) is %d\n", a, b, Max(a, b));
1668    return 0;
1669}
1670```
1671
1672Due 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:
1673
1674```
1675MACRO: max of a(1) and b(-1) is -1
1676FUNC : max of a(1) and b(-1) is 1
1677```
1678
1679The 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).
1680Therefore, the C99 standard introduces inline functions (gcc introduces inline functions ahead of this standard).
1681
1682The 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.
1683Inline functions have the advantages of both functions and macros:
1684
1685- Strict type checking is performed for inline functions and functions.
1686- Each input parameter of an inline function or function is calculated only once.
1687- Inline functions are unfolded in place and there is no overhead for function calls.
1688- Inline functions are better optimized than standard functions.
1689
1690For performance-sensitive code, consider using inline functions instead of function-like macros.
1691Functions and inline functions cannot completely replace function-like macros, since function-like macros are more suitable for certain scenarios.
1692For example, in a log scenario, using a function-like macro with variable parameters and default parameters is more convenient.
1693
1694```c
1695int ErrLog(const char *file, unsigned long line, const char *fmt, ...);
1696#define ERR_LOG(fmt, ...) ErrLog(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
1697```
1698
1699### <a name="r6-1"></a>Rule 6.1 Use complete parentheses for macro parameters when defining a macro.
1700
1701The 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.
1702
1703The expression after combination may result in a different result than expected, especially when the macro parameter is in an expression.
1704
1705The following is an incorrect format:
1706
1707```c
1708#define SUM(a, b) a + b         // Bad
1709```
1710
1711When the macro is used, the execution result is inconsistent with the expected result.
1712
1713`100 / SUM(2, 8)` is expanded to `(100 / 2) + 8`. The expected result is `100 / (2 + 8)`.
1714
1715This problem can be solved by adding parentheses to the entire expression, as shown in the following:
1716
1717```c
1718#define SUM(a, b) (a + b)       // Bad
1719```
1720
1721However, this method has the following problems:
1722
1723`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`.
1724
1725To solve this problem, add parentheses to each macro parameter, as shown in the following:
1726
1727```c
1728#define SUM(a, b) (a) + (b)     // Bad
1729```
1730
1731The 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`.
1732
1733In conclusion, the correct format is as follows:
1734
1735```c
1736#define SUM(a, b) ((a) + (b))   // Good.
1737```
1738
1739Avoid abusing parentheses. As shown in the following, adding parentheses to a single identifier or a positive number is meaningless.
1740
1741```c
1742#define SOME_CONST      100     // Good: No parentheses needed for a single positive number.
1743#define ANOTHER_CONST   (-1)    // Good: Parentheses needed for a negative number.
1744
1745#define THE_CONST SOME_CONST    // Good: No parentheses needed for a single identifier.
1746```
1747
1748Notes:
1749
1750- Do not add parentheses to macro parameters when they are involved in the '#' or '##' operation.
1751- Do not add parentheses to macro parameters when they are used for string concatenation.
1752- If a macro parameter is used as a separate part in one side of an assignment expression (including +=, -=, etc.), parentheses are not required.
1753- If a macro parameter is used as a separate part in comma expressions, functions or macro call lists, parentheses are not required.
1754
1755Example:
1756
1757```c
1758#define MAKE_STR(x) #x                  // No parentheses for 'x'
1759
1760#define HELLO_STR(obj) "Hello, " obj    // No parentheses for 'obj'
1761
1762#define ADD_3(sum, a, b, c) (sum = (a) + (b) + (c)) // 'a', 'b', and 'c' need parentheses, whereas 'sum' does not.
1763
1764#define FOO(a, b) Bar((a) + 1, b)       // 'a' needs parentheses, whereas 'b' does not.
1765```
1766
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)`.
1768
1769Macros 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.
1770
1771Incorrect example:
1772
1773```c
1774// Not Good
1775#define FOO(x) \
1776    (void)printf("arg is %d\n", (x)); \
1777    DoSomething((x));
1778```
1779
1780When 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.
1781
1782```c
1783for (i = 1; i < 10; i++)
1784    FOO(i);
1785```
1786
1787To solve the preceding problem, use braces to enclose the statements defined by `FOO`.
1788
1789```c
1790#define FOO(x) { \
1791    (void)printf("arg is %d\n", (x)); \
1792    DoSomething((x)); \
1793}
1794```
1795
1796The brackets are not associated with semicolons (;). The semicolon following the braces is another statement.
1797
1798In the following code example, the "suspended else' compilation error message is displayed.
1799
1800```c
1801if (condition)
1802    FOO(10);
1803else
1804    FOO(20);
1805```
1806
1807The correct format is to wrap the executed body using a `do-while(0)`, as shown in the following:
1808
1809```c
1810// Good
1811#define FOO(x) do { \
1812    (void)printf("arg is %d\n", (x)); \
1813    DoSomething((x)); \
1814} while (0)
1815```
1816
1817Exceptions:
1818
1819- Macros that contain 'break' or 'continue' statements can be treated as exceptions. Do use these macros carefully.
1820- 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.
1821- An exception can be a non-multiple statement, or a single `if`, `for`, `while`, or `switch` statement.
1822
1823### <a name="r6-3"></a>Rule 6.3 Do not pass expressions with side effects to a function-like macro.
1824
1825Since 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.
1826
1827As 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.
1828
1829```c
1830#define SQUARE(a) ((a) * (a))
1831
1832int a = 5;
1833int b;
1834b = SQUARE(a++);    // Bad: 'a' is added twice.
1835```
1836
1837`SQUARE(a++)` is expanded to `((a++) * (a++))` the variable `a` is added twice, and its value is `7` instead of the expected `6`.
1838
1839The correct format is as follows:
1840
1841```c
1842b = SQUARE(a);
1843a++; // Result: a = 6, which is added only once.
1844```
1845
1846In addition, if the macro parameter contains a function call, the function may be called repeatedly after the macro is expanded.
1847
1848If 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.
1849
1850### Rec 6.2 Exercise caution when you use the statements such as `return`, `goto`, `continue`, and `break` in a function-like macro definition.
1851
1852Although 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.
1853
1854First, the macro encapsulation of the `return` statement can easily lead to excessive encapsulation and use.
1855As 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.
1856
1857```c
1858#define LOG_AND_RETURN_IF_FAIL(ret, fmt, ...) do { \
1859    if ((ret) != OK) {                             \
1860        (void)ErrLog(fmt, ##__VA_ARGS__);          \
1861        return (ret);                              \
1862    }                                              \
1863} while (0)
1864
1865#define RETURN_IF(cond, ret) do {                  \
1866    if (cond) {                                    \
1867        return (ret);                              \
1868    }                                              \
1869} while (0)
1870
1871ret = InitModuleA(a, b, &status);
1872LOG_AND_RETURN_IF_FAIL(ret, "Init module A failed!"); // OK
1873
1874RETURN_IF(status != READY, ERR_NOT_READY);  // Bad: The most important logic is not obvious.
1875
1876ret = InitModuleB(c);
1877LOG_AND_RETURN_IF_FAIL(ret, "Init module B failed!"); // OK
1878```
1879
1880Second, if `return` is encapsulated in a macro, it may also cause a memory leak. Example:
1881
1882```c
1883#define CHECK_PTR(ptr, ret) do { \
1884    if ((ptr) == NULL) { \
1885        return (ret); \
1886    } \
1887} while (0)
1888
1889...
1890
1891mem1 = MemAlloc(...);
1892CHECK_PTR(mem1, ERR_CODE_XXX);
1893
1894mem2 = MemAlloc(...);
1895CHECK_PTR(mem2, ERR_CODE_XXX);  // Wrong: Memory leak.
1896```
1897
1898If `mem2` fails to apply for memory, `CHECK_PTR` will return a message instead of releasing `mem1`.
1899
1900Besides, 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.
1901
1902In summary, it is not recommended to encapsulate process changing statements, such as `return`, `goto`, `continue`, and `break`, in macro definitions.
1903
1904However, these macros can be used in special scenarios, such as return value judgment.
1905
1906Note: **Macro names must contain descriptive keywords if process changing statements, such as `return`, `goto`, `continue`, and `break`, are used.**
1907
1908### Rec 6.3 Include no more than 10 lines in a function-like macro (excluding blank lines and comments).
1909
1910A function-like macro is more difficult to debug and locate than a function, especially when the macro is too long.
1911Macro expansion will also lead to more compiled code. It is recommended that function-like macros contain no more than 10 lines.
1912
1913# 7 Variables
1914
1915In C language coding, variables are the most important except for functions.
1916
1917When using a variable, you should always follow the principle of "single responsibility".
1918
1919By scope, variables can be classified into global variables and local variables.
1920
1921## Global Variables
1922
1923Do not use or avoid using global variables.
1924
1925In program design, global variables are variables that are accessible to all scopes. Using unnecessary global variables is generally considered a bad habit.
1926
1927Disadvantages of global variables:
1928
1929- Destroys the independence and portability of a function. Functions can be dependent on global variables and increased coupling results.
1930- 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.
1931- In a concurrent programming environment, global variables will hinder reentry of functions. Additional synchronization protection must be added to ensure data security.
1932
1933If unavoidable, the read and write of global variables should be encapsulated in a centralized manner.
1934
1935### Rule 7.1 Do not use global variables as interfaces between modules.
1936
1937Global variables are for the internal implementation of modules and should not be exposed as interfaces.
1938
1939Global 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.
1940
1941## Local Variables
1942
1943### Rule 7.2 Do not use uninitialized variables as rvalues.
1944
1945The variable here refers to a local dynamic variable, and also includes a memory block obtained on a memory heap.
1946
1947Because their initial values are unpredictable, it is prohibited to use them directly as rvalues without effective initialization.
1948
1949```c
1950void Foo(...)
1951{
1952    int data;
1953    Bar(data);  // Bad: Uninitialized variables are used as rvalues.
1954    ...
1955}
1956```
1957
1958If there are different branches, ensure that all branches are initialized before being used as rvalues.
1959
1960```c
1961void Foo(...)
1962{
1963    int data;
1964    if (...) {
1965        data = 100;
1966    }
1967    Bar(data);  // Bad: This value is not initialized in some branches.
1968    ...
1969}
1970```
1971
1972Uninitialized rvalues can be found by generic static check tools.
1973
1974For example, the PCLint tool reports a warning for the following two examples.
1975
1976> Warning 530: Symbol 'data' (line ...) not initialized
1977>
1978> Warning 644: Variable 'data' (line ...) may not have been initialized
1979
1980### Rule 7.3 Forbid invalid and redundant variable initialization.
1981
1982If 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.
1983
1984Common redundant initialization:
1985
1986```c
1987int cnt = 0;    // Bad: Redundant initialization. It will be overwritten by later initialization.
1988...
1989cnt = GetXxxCnt();
1990...
1991```
1992
1993Variables with conditional values can be initialized to default values during definition.
1994
1995```c
1996char *buf = NULL;   // Good: NULL as the default value
1997if (condition) {
1998    buf = malloc(MEM_SIZE);
1999}
2000...
2001if (buf != NULL) {  // Check whether memory has been allocated.
2002    free(buf);
2003}
2004```
2005
2006Even worse, redundant clearing for arrays may affect the performance.
2007
2008```c
2009char buf[VERY_BIG_SIZE] = {0};
2010memset(buf, 0, sizeof(buf));    // Bad: Redundant clearing
2011```
2012
2013Invalid initialization, which hides a more severe problem:
2014
2015```c
2016void Foo(...)
2017{
2018    int data = 0;   // Bad: regular initialization
2019
2020    UseData(data);          // UseData should be placed after GetData.
2021    data = GetData(...);    // Get data.
2022    ...
2023}
2024```
2025
2026In 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
2028However, due to invalid initialization, the defect of placing "UseData" before "GetData" cannot be easily found.
2029
2030Therefore, simple code should be written to initialize variables or memory blocks as required.
2031
2032The 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
2034This 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
2036If this compilation environment is supported, you are advised to define local variables in this way.
2037
2038**Exceptions:**
2039
2040**As 'Secure Coding Standard' required, pointers, resource variables, and boolean variables can be treated as exceptions of this rule.**
2041
2042### Rule 7.4 Do not use magic numbers.
2043
2044The so-called magic numbers are the numbers that are unintelligible and difficult to understand.
2045
2046The magic number is not a concept that can be defined literally. It varies depending on context and service knowledge.
2047
2048For example, the number 12 varies in different contexts.
2049
2050`type = 12;` is not intelligible, but `month = year * 12;` can be understood.
2051
2052The number 0 is sometimes seen as a magic number. For example, the `status = 0;` cannot truly express any status information.
2053
2054Solution:
2055
2056Comments can be added for numbers that are used only once.
2057
2058For numbers that are used multiple times, macro or const variables must be defined and self-commented with symbolic naming.
2059
2060The following cases are forbidden:
2061
2062The name is not used to explain the meaning of a number, for example, `#define ZERO 0`.
2063
2064The value is limited by the name, for example, `#define XX_TIMER_INTERVAL_300MS 300`.
2065
2066# 8 Programming Practice
2067
2068## Expressions
2069
2070### Rec 8.1 When comparing expressions, follow the principle that the left side tends to change and the right side tends to remain unchanged.
2071
2072When 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.
2073
2074The constant should be placed on the right according to the normal reading order and habit. The expression is written as follows:
2075
2076```c
2077if (v == MAX) ...
2078if (v < MAX) ...
2079```
2080
2081There 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.
2082
2083You 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.
2084
2085### Do not reference a variable again in an expression containing an increment (++) or decrement (--) operator.
2086
2087In 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
2089For better portability, you should not make any assumptions about the operation sequence not defined in any standards.
2090
2091Note that this problem cannot be solved by using parentheses because it is not a problem of priority.
2092
2093Example:
2094
2095```c
2096x = b[i] + i++; // Bad: b[i] operation and i++, the order is not clear.
2097```
2098
2099The correct way is to add a separate line of increment or decrement:
2100
2101```c
2102x = b[i] + i;
2103i++;            // Good: Single line.
2104```
2105
2106Function parameter:
2107
2108```c
2109Func(i++, i);   // Bad: When passing the second parameter, it is not sure whether the increment operation has occurred.
2110```
2111
2112The correct way:
2113
2114```c
2115i++;            // Good: Single line.
2116x = Func(i, i);
2117```
2118
2119### Rec 8.2 Use parentheses to specify the sequence of expressions, instead of using the default priority.
2120
2121Parentheses 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
2123However, too many parentheses muddy the code, reducing readability. Use them moderately.
2124
2125Parentheses are recommended when expressions contain operators that are not commonly used and are confusing, such as bitwise operators.
2126
2127```c
2128c = (a & 0xFF) + b;     /* Parentheses are required while using bit operators. */
2129```
2130
2131## Statements
2132
2133### Rule 8.2 Provide a 'default' branch for the `switch` statement.
2134
2135In 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.
2136
2137Exceptions:
2138
2139If the switch condition variable is of the enum type and the case branches cover all values, then the default branch is redundant.
2140
2141A modern compiler can check whether the case branch of some enumerated values is missing in the switch statement. A warning will be displayed.
2142
2143```c
2144enum Color {
2145    RED,
2146    BLUE
2147};
2148
2149// The switch condition variable is an enumerated value. Therefore, you do not need to add the 'default' processing branch.
2150switch (color) {
2151    case RED:
2152        DoRedThing();
2153        break;
2154    case BLUE:
2155        DoBlueThing();
2156        ...
2157        break;
2158}
2159```
2160
2161### Rec 8.3 Exercise caution when using the `goto` statement.
2162
2163The `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.
2164
2165The `goto` statement is used to implement function return to a single point within a function.
2166
2167If 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.
2168
2169Example:
2170
2171```c
2172// Good: Use a goto statement to implement function return at a single point.
2173int SomeInitFunc(void)
2174{
2175    void *p1;
2176    void *p2 = NULL;
2177    void *p3 = NULL;
2178
2179    p1 = malloc(MEM_LEN);
2180    if (p1 == NULL) {
2181        goto EXIT;
2182    }
2183
2184    p2 = malloc(MEM_LEN);
2185    if (p2 == NULL) {
2186        goto EXIT;
2187    }
2188
2189    p3 = malloc(MEM_LEN);
2190    if (p3 == NULL) {
2191        goto EXIT;
2192    }
2193
2194    DoSomething(p1, p2, p3);
2195    return 0;   // OK.
2196
2197EXIT:
2198    if (p3 != NULL) {
2199        free(p3);
2200    }
2201    if (p2 != NULL) {
2202        free(p2);
2203    }
2204    if (p1 != NULL) {
2205        free(p1);
2206    }
2207    return -1;  // Failed!
2208}
2209```
2210
2211## Type Conversion
2212
2213### Rec 8.4 Minimize unnecessary type conversion and forced conversion.
2214
2215When 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.
2216
2217In the following assignment, most compilers do not generate warnings, but the values are slightly changed.
2218
2219```c
2220char ch;
2221unsigned short int exam;
2222
2223ch = -1;
2224exam = ch; // Bad: Compilers does not generate any warnings. In this case, the value of exam is 0xFFFF.
2225```
2226