C language programming style and specification under Linux

Linux has a unique programming style, which is described in detail in the kernel source code directory Documentation/CodingStyle.

I suggest you take a look at it. It’s still very interesting for foreigners to write technical documents. When they come up, they will go crazy, "You will be finished if you don’t write like this. Heretics don’t write like this..." It’s not as rigid as in China. Read more English documents. Technological growth helps.

1. Naming convention

In general programming, it is customary to name macros, variables, and functions as follows:

#define PI 3.1415926 /*用大写字母代表宏 */
int minValue, maxValue; /*变量:第一个单词全小写,其后单词的第一个字母大写*/
void SendData (void); /* 函数:所有单词第一个字母都大写 */

This method of distinguishing words by initial capitalization is very popular. Whether the first letter of the first word is capitalized can distinguish whether the name belongs to a variable or a function, and seeing the entire string of capital letters can be concluded as a macro.

Program development in many fields follows this convention.

But Linux does not use this convention to name, for the above program, it will be named in Linux:

#define PI 3.1415926
int min_value, max_value;
void send_data (void);

In the above naming method, macros are still capitalized, but variable and function names do not use capital letters to distinguish words according to Windows, but use underscores . And naming under Linux, it is best to use long and accurate descriptions for global variables, and short local variables, or even directly use tmp, i and the like .

In fact, both naming methods are fine. When writing programs under Liunx, it is better to be consistent with the code style of the Linux community, but I think it is harmless if you use the first one.

2. Indent

Use "TAB" instead of space brackets for indentation.

Another mention: Under Linux, "TAB" represents 8 characters, not 4, and the Linux code style believes that 8 characters can better reflect the hierarchical structure. Those who spray "TAB" with 4 characters in the document are heretics. For the problem that the code is too right when 8 characters are in multiple levels, if the document is sprayed with more than three levels, your code will be finished, hahaha.

In order to reduce the level, in terms of switch/case statements, Linux recommends that switch and case are aligned, for example:

switch (suffix) {
case 'G':
case 'g':
    mem <<= 30;
    break;
case 'M':
case 'm':
    mem <<= 20;
    break;
case 'K':
case 'k':
    mem <<= 10;
    /* fall through */
default:
    break;
}

3. The principle of using code brackets "{" and "}" in Linux

1) For structures, if/for/while/switch statements, "{" does not start a new line , for example:

struct var_data {
    int len;
    char data[0];
};

if (a == b) {
    a = c;
    d = a;
}

for (i = 0; i < 10; i++) {
    a = c;
    d = a;
}

2) If there is only one line after the if and for loops, do not add "{" and "}", for example:

for (i = 0; i < 10; i++) {
     a = c;
}

should be changed to:

for (i = 0; i < 10; i++) 
    a=c;

3) When if and else are used together, the else statement does not start a new line , for example:

if (x == y){
    ...
} else if (x > y) {
    ...
} else {
    ...
}

4) For functions, "{" starts a new line , for example:

int add (int a, int b)
[
    return a + b;
}

4. Use of spaces

1) Add a space after the keyword

Put spaces after these keywords:

if, switch, case, for, do, while

But these do not add:

sizeof, typeof, alignof,  __attribute__

For example:

 s = sizeof(struct file);

2) Within the brackets, next to the brackets without spaces

Error demonstration:

s = sizeof( struct file );

3) For pointers, the "*" sign is next to the name instead of the type

For example:

    char *linux_banner;
    unsigned long long memparse(char *ptr, char **retptr);
    char *match_strdup(substring_t *s);

4) Add spaces on both sides of the operator

The following binary or ternary operators are surrounded by spaces:

    =  +  -  <  >  *  /  %  |  &  ^  <=  >=  ==  !=  ?  :

But the following unary operators, without spaces:
    & * + - ~ ! sizeof typeof alignof __attribute__ defined

Increment and decrement symbols. Without spaces:
    ++ --

Struct member operators, without spaces:

 '.' and "->" 

Do not put spaces at the end of the line.

5. Functions

Functions should be concise and do one thing. Function length should be limited to one or two screens (ISO/ANSI screen size is 80x24).

If you have a conceptually simple function, it's okay to use a longer function, such as a case inside the function.

In source files, separate functions with blank lines. If a function is exported, its EXPORT* macro should immediately follow the closing function brace line. For example:


int system_is_up(void)
{
	return system_state == SYSTEM_RUNNING;
}
EXPORT_SYMBOL(system_is_up);

6. Use of goto statement

Whether to use goto has always been a well-known controversial topic. The application of goto in the Linux kernel source code is very extensive, but it is generally limited to error handling. Its structure is as follows:

if(register_a() != 0)
    goto err;
if (register_b() != 0)
    goto errl;
if(register_c() != 0)
    goto err2;
if (register_d () != 0)
    goto err3;
err3: 
    unregister_c();
err2: 
    unregister_b ();
errl: 
    unregister_a ();
err: 
    return ret;

This usage of using goto for error handling is really simple and efficient. You only need to ensure logout, resource release, etc. during error handling, which is opposite to the normal registration and resource application sequence.

7. Notes

Linux-style comments are c89 "/*…*/" style. Do not use C99-style "//..." comments.

The preferred style for long (multi-line) comments is:

	/*
	 * This is the preferred style for multi-line
	 * comments in the Linux kernel source code.
	 * Please use it consistently.
	 *
	 * Description:  A column of asterisks on the left side,
	 * with beginning and ending almost-blank lines.
	 */

8.do {} while(0) statement

In the Linux kernel, you often see statements like do {} while (0).

Many people will be confused at first, thinking that do while(0) is meaningless, because it will only be executed once, the effect is exactly the same with or without do {} while(0), in fact, the usage of do {} while(0) is mainly Used in macro definitions.

Here is a simple macro to demonstrate:

#define SAFE_FREE (p) do{ free (p); p = NULL;}  while (0)

Assuming that do...while(0) is removed here, SAFE_DELETE is defined as:

#define SAFE FREE (p) free (p); p = NULL;

Then the following code:

if (NULL != p)
    SAFE_DELETE(p)
else
    .../* do something */

would be expanded to:

if (NULL != P)
    free (p); p = NULL;
else
    .../* do something */

There are two problems in the unrolled code:

1) Because there are two statements after the if branch, the else branch does not have a corresponding if, and the compilation fails.

2) Assuming there is no else branch, the second statement in SAFE_FREE will be executed no matter whether the if test passes or not.

Indeed, adding {} to the definition of SAFE_FREE can solve the above problem, namely:

#define SAFE_FREE (p) { free (p); p= NULL; }

Thus, the code:

if (NULL != p)
    SAFE_DELETE(p)
else
    ... /* do something */

would be expanded to:

if (NULL != p)
    { free (p); P = NULL; }
else
    .../* do something */

However, in a C program, it is a customary habit to add a semicolon after each statement, then, the following code:

if (NULL != p)
    SAFE_DELETE (p);
else
    .... /* do something */

will be expanded to:

if (NULL != p)
    { free (p); p = NULL; };
else
    .../* do something */

In this way, the else branch has no corresponding if, and the compilation will fail.

Assuming that the do {} while(0) statement is used, the situation is different, and the same code will be expanded as:

if (NULL != p)
    do{ free (p); p= NULL; } while (0);
else
    .../* do something */

without compiling problems. The use of do{} while(0) is entirely to ensure that users of the macro definition can use the macro without compilation errors, and it does not make any assumptions about its users.

9. Other provisions

1. In principle, do not use typedef, Linux believes that typedef will make readable and writable worse

2. Inline functions usually do not exceed three lines

 

Guess you like

Origin blog.csdn.net/freestep96/article/details/127155084