嵌入式、单片机C语言编程规范、风格、习惯

前言:磨刀不误砍柴,良好的编程规范毫无疑问会助力提高编程效率。华为2011年的C语言编程规范长达61页,对实际工程中的应该如何规避编程陋习做出了很详细的指导,适合经常阅读反复学习,实践和理论指导统一,实现逐步提高。

61页的指导不是要求你囫囵吞枣,而是细嚼慢咽,意识常在,没事就翻翻

下面是自己的编程习惯以及一些关于华为C语言规范等文档阅读的笔记总结,更新是不定时的。

一、注释/代码片段

  • 诉求:预先编辑好一些有格式的注释(文件头注释、函数头注释等)、宏(条件编译等),以实现在需要的地方整段输入。

  • 达到的效果:根据已建立的代码片段模板,在写代码时直接输入提示符,按Tab键能够快速定位下一个编辑点,同时也可以多个位点同时输入。

实现步骤

说明:每个软件工程师都应该拥有一款适合自己的文本/代码编辑器,这里以微软家族的Visual Code来具体实现这一诉求。

Visual Code上配置用户代码片段配置用户代码片段

Visual Code下,使用快捷键Ctrl+Shift+P,输入user snippet,敲击回车

我们将所配置的代码片段应用在所有文件类型上,即点击新建全局代码片段

输入任意文件名,回车即可

“my code description” :代码块的描述。
“scope” :所用的语言类型,如果你用的是C,其值改成C。
“prefix”:所用的快捷键提示。
“body”:代码块内容,类似照着填。

这是我的配置(文件头注释、文件头修改注释、函数头注释、步骤描述、分隔等、),你可以在此基础上进行修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
{
    // Place your global snippets here. Each snippet is defined under a snippet name and has a scope, prefix, body and 
    // description. Add comma separated ids of the languages where the snippet is applicable in the scope field. If scope 
    // is left empty or omitted, the snippet gets applied to all languages. The prefix is what is 
    // used to trigger the snippet and the body will be expanded and inserted. Possible variables are: 
    // $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders. 
    // Placeholders with the same ids are connected.
    // Example:
    // "Print to console": {
    //  "scope": "javascript,typescript",
    //  "prefix": "log",
    //  "body": [
    //      "console.log('$1');",
    //      "$2"
    //  ],
    //  "description": "Log output to console"
    // }
    "File head": {
        "prefix": "commonts_fihd",
        "body": [
            "/****************************************************",
            " *  Copyright (c) xxxxxxxxxxxxxxxxx",
            " *  All rights reserved.",
            " *  File name:     $$TM_FILENAME",
            " *  Description:   $1",
            " *  History:",
            " *  1. Version:    $2",
            " *      Date:      $CURRENT_YEAR-$CURRENT_MONTH-$CURRENT_DATE",
            " *      Author:    jbs",
            " *      Modify:    $3",
            " *",
            " ***************************************************/",
            "$0"
        ],
        "description": "文件说明头"
    },
    "History": {
        "prefix": "commonts_hist",
        "body": [
            " *  $1. Version:    $2",
            " *      Date:      $CURRENT_YEAR-$CURRENT_MONTH-$CURRENT_DATE",
            " *      Author:    jbs",
            " *      Modify:    $3",
            " *",
            "$0"
        ],
        "description": "文件说明头中的历史记录"
    },
    "Function head": {
        "prefix": "commonts_fchd",
        "body": [
            "/**************************************",
            " * Name:   ${1:}",
            " * Brief:  ${2:}",
            " * Input:  ${3:@param1:}",
            " * Output:  ${4:None}",
            " * Author: jbs, Date: $CURRENT_YEAR-$CURRENT_MONTH-$CURRENT_DATE",
            " **************************************/",
            "$0",
        ],
        "description": "函数说明头"
    },
    "ifndef": {
        "prefix": "commonts_#ifn",
        "body": [
            "#ifndef __$1",
            "#define __$1",
            "",
            "$0",
            "",
            "#endif /* __$1 */",
            ""
            ],
        "description": "头文件保护前缀"
    },
    "comment": {
        "prefix": "commonts_cc",
        "body": "/* $1 */$0",
        "description": "单行块注释"
    },
    "Modify description": {
        "prefix": "commonts_mdfy",
        "body": [
            "/**",
            " * @start   $CURRENT_YEAR-$CURRENT_MONTH-$CURRENT_DATE Modify by thy.",
            " * @brief   ${1:sth}",
            " */",
            "$0",
            "/**",
            " * @end",
            " */"],
        "description": "修改说明"
    },
    "comments_head":{
        //"scope": "c,h",
        "prefix": "comments_head",
        "body": [
            "/**",
            "  *****************************【File】******************************",
            "  * file_name:$TM_FILENAME",
            "  * author: jbs, website: https://scrazy.cn",
            "  * vertion:1.0",
            "  * date: $CURRENT_YEAR-$CURRENT_MONTH-$CURRENT_DATE",
            "  * brief: ${2:}",
            "  *******************************************************************",
            "  * attention:",
            "  *   ${3:}",
            "  *******************************************************************/",
            "$0",
        ],
        "description": "文件头部注释"
    },
    "comments_func":{
        //"scope": "c",
        "prefix": "comments_func",
        "body": [
            "/**",
            "  ********************【Function】**********************",
            "  * name:  ${1:}",
            "  * author: jbs, date: $CURRENT_YEAR-$CURRENT_MONTH-$CURRENT_DATE, website: https://scrazy.cn",
            "  * brief: ${2:}",
            "  *****************************************************/",
            "$0",
        ],
        "description": "函数头注释"
    },
    "Divide Line":{
        //"scope": "c",
        "prefix": "comments_line",
        "body": [
            "/*------------------------- ${1:} ---------------------------*/",
            "$0",
        ],
        "description": "分割线"
    },
    "Frame Information":{
        //"scope": "c",
        "prefix": "commonts_frame",
        "body": [
                "/*==========↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓==========*/",
                "    /* 《==== ${1:} ====》", 
                "       <tips: ${2:}     > */",
                "    ",
                "    ",
                "/*==========↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑==========*/",
                "$0",
        ],
        "description": "框框"
    },
    "Imporatnt Information":{
        //"scope": "c",
        "prefix": "commonts_impotrant",
        "body": [
            "/* ★★★★★★★★★★★★★★★",
            " *  ${1:}",
            " * ★★★★★★★★★★★★★★★*/",
            "$0",
        ],
        "description": "重要信息"
    },
    "Module Step":{
        //"scope": "c",
        "prefix": "commonts_step",
        "body": [
                "/*------ STEP1:${1:} -----*/",
                "$0",
        ],
        "description": "步骤描述"
    },
}

二、文件、变量、结构体、函数命名

文件名

  • 文件名:建议全部小写命名,下面是华为说的

变量

  • 变量命名风格:建议nuix风格

某公司的编程规范建议unix风格

个人喜欢unix风格,因为大小写切换真的是很烦,中英文切换就更烦了

  • 变量命名前缀:全局变量g前缀,静态变量s前缀,指针变量p前缀

结构体

使用typedef对结构体取别名时,以“_t”结尾

全局变量使用全局结构体封装所有变量,例如

1
2
3
4
5
typedef struct tag_param
{
uint8_t lora_init_flag;
uint32_t point_num;
}g_param_t;

函数

其他

常见的通用单词进行缩写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
argument 缩写为 arg
buffer 缩写为 buff
clock 缩写为 clk
command 缩写为 cmd
compare 缩写为 cmp
config/configuration 缩写为 cfg
device 缩写为 dev
error 缩写为 err
hexadecimal 缩写为 hex
increment 缩写为 inc、
initialize 可写为 init
maximum 缩写为 max
message 缩写为 msg
minimum 缩写为 min
parameter 可缩写为 param
previous 缩写为 prev
register 缩写为 reg
semaphore 缩写为 sem //信号量
statistic 缩写为 stat
receive recv
source src
destination dst
count cnt
delete del
define def
frequency freq
length len
value val
string str
optimization opt //最佳;最优
synchronize 缩写为 sync
temp 缩写为 tmp
table tab
postion pos

常见的互斥意义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
add/remove
begin/end
create/destroy
insert/detach
first/last
increment/decrement
put/get
create/delete
lock/unlock
open/close
min/max
old/new
start/stop
next/previous
source/target
show/hide
send/receive
copy/paste
up/down
pop/push
start/stop

三、其他知识点

在华为2011年的C编程规范里有很多值得认真我们学习的编程规范,这里仅罗列很小的一部分

头文件依赖的传导会导致编译时间上升,需要合理包含头文件

减少全局变量的使用

头文件里放声明,通常一个C文件对应一个头文件,C文件里禁止通过extern使用外部接口

头文件是模块对外的接口,头文件里放对外提供的函数声明、宏定义、类型定义,注意尽可能不存放对外变量的声明,即尽可能不使用全局变量作为接口 ,华为文档里多次提到这一点,尽可能甚至是杜绝这种方法

新增函数不要超过50行

代码嵌套不要超过4层

扇出要合理,通常是3-5

函数非参输入,必须检查有效性

源文件内部所有声明和定义的函数,应增加static关键词

【下次编辑点】

华为2011 C编程规范:

https://share.babel.cc/share.do?s=NzM2MTAwNjg1ODM1MjMyNTtXZWQgQXVnIDEyIDIwMjAgMjA6Mjk6MjQgR01UKzA4MDAgKEdNVCswODowMCk=

Rt-thread编程规范:

https://github.com/RT-Thread/rt-thread/blob/master/documentation/coding_style_cn.md