嵌⼊式LinuxC代码规范和风格
嵌⼊式Linux C代码规范和风格
本⽂档为作者在嵌⼊式和嵌⼊式 linux C 语⾔的学习和⼯作中所总结的代码规范,是作者从 STM32 单⽚机开发向 Linux C 开发的时候为了摆脱遗留的编码规范陋习⽽编写的。因此,本⽂档主要⾯向 Linux C,会根据实际情况兼容单⽚机的开发。⽂档主要以 Linux 源码下的CodingStyle ⽂档为蓝本⽽编写,本⽂档主要是为了解决作者的实际需求,并不能照顾到所有的开发⼈员,因此编码规范可能不适
合某些程序员朋友。参考:
1 、Linux 源码下的《 《CodingStyle》 》 ⽂档。
2、 、 《代码整洁之道》。
3、 、《 《GNU 编码规范》。
4 、《华为技术有限公司 c 》 语⾔编程规范》。
套⽤ CodingStyle 下的⼀句话:
“代码风格是因⼈⽽异的,⽽且我不愿意把⾃⼰的观点强加给任何⼈,但这就
像我去做任何事情都必须遵循的原则那样,我也希望在绝⼤多数事上保持这种的
态度。”
1.规范说明:
之所以会写这份⽂档是要下定决⼼修改⾃⼰那写的跟⼀坨屎⼀样的垃圾代码规范!相信正
在阅读本⽂档的读者出发点也是如此(可能你的代码规范还没有像⼀坨屎那么严重)。因为作者
⼯作内容的原因(做单⽚机开发板的),此前没有代码规范化的思维,变量,函数的命名随⼼所
欲,⼤⼩写混⽤;代码注释“//”和“/* */”混⽤等等很多陋习,这样的陋习写出的例程供阅读
者学习也会带坏⼈家哒,所以痛定思痛,⼀定要改掉这些陋习。在这个看脸的时代,优美的代
码风格让⼈看着都赏⼼悦⽬。
当然,代码规范和风格不是⽤来赏⼼悦⽬的,要不然就是花瓶了,代码规范和风格的⽬的
是要编写出简洁明了、可维护、可测试、可靠、可移植、⾼效的代码。
1.1.简单,明了,清晰:
代码写出来重点是给⼈看的,因此简单、明了、清晰是第⼀要务!代码的可阅读性要⾼于
代码的性能(除⾮你的代码以后不需要维护,那你写成啥样都⽆所谓)。简单、明了、清晰的代码
也利于后期维护,尤其是当你写的代码交给他⼈去维护的时候,请不要祸害别⼈!
1.2:精髓:
代码越长越难看懂,这个⼤家应该都深有体会,⼀个 1000 多⾏的函数和⼀个最多 100 ⾏的函数哪个好看?所以尽量将把函数写的精简。⽽且代码越长越容易出错,没有⽤的代码,变量等⼀定要及时的清理掉!功能类似或者重复的代码应尽可能提炼成⼀个函数。
1.3:尽量与原有代码风格保持⼀致:
⼀个公司内部的代码风格⼀般都是统⼀的,但是如果你跳槽到其他公司去,或者有时候因
为业务原因需要维护别的公司的代码,此时代码风格出现冲突的话尽可能使⽤现在维护的代码风格。
1.4:减少封装:
此规则仅适⽤于作者所在公司,作者公司是做开发板的,所写的所有例程代码都需要开源给客户阅读学习。在编写的过程中会遇到使⽤很多第三⽅库,⽐如 ST 的 HAL 库、NXP 的 FSL库,LWIP 协议栈、UCOS 操作系统、FreeRTOS 操作系统等等,这些第三⽅库的编码规范和风格各不相同。有⼈为了统⼀⾃⼰的编码风格会对这些第三⽅库的 API 函数做封装,如果是做产品的话这样做⽆可厚⾮,毕竟为了代码风格的统⼀,但是作为做开发板的,尽量不要对第三⽅库做封装!因为每⼀次封装都会将原有 API 函数的本意遮蔽,读者第⼀眼看懂这个API 函数的具体函数,⽐如 ST 官⽅的 Cube 库⾥⾯就为了兼容⾃⼰的代码风格,对 FreeRTOS 的 API 函数做了封装,结果很多客户就问我们为何 ST 官⽅所调⽤的任务创建函数和我们的 FreeRTOS 教程不同!他们之间有什么区别?他们之间没有任何区别,只是 ST 对其做了⼀个简单的封装,结果给学习者带来了困惑!如果不做这个封装的话虽然影响到了代码风格的统⼀,但是却给学习者减少了困惑,提⾼了学习效率,⽽提⾼客户的学习效率是我们公司的第⼀宗旨!
2.排版格式和注释:
排版是为了在编写代码的时候按照“⼀定的规矩”来编写,主要⽬的是为了是代码清晰、易于阅读。注释顾名思义就为注释⾃⼰的代码,以⽅便他⼈阅读,尤其是尤其维护⼈员。优美的排版和⾔简意赅的注释可以提⾼阅读者的阅读效率,所以在编写代码之前⼀定要确定好⾃⼰打算采⽤的排版⽅式和注释⽅式。
华为linux和windows的区别2.1:排版格式:
2.1.1:代码缩进:
代码缩进要使⽤制表符,也就是 TAB 键,不要使⽤空格键缩进!⼀般情况下⼀个 TAB 为4 个字符,但是 Linux 建议 TAB 键为 8 个字符,因为 8 个字符缩进⽐较多,因为有利于长时间阅读代码,可以很清晰的分辨出多级嵌套,但是 8 个字符太多,代码向右移动的太远了,这样的话如果屏幕横向分辨率⼩的话每⾏编写的代码就会少,尤其是当⼀个代码块有多级缩进的时候,Linux 建议你应该修改你的代码。这⾥我设置的 TAB 键为 4 个字符,因为在我阅读 Linux内核源码的时候发现⼤部分都是 4 个字符。
在 switch 语句中,“swich”和“case”标签应该对齐处于同⼀列,不需要缩进 case 标签,
如下所⽰:
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;
}
2.1.2:代码⾏相关规范:
1、 每⼀⾏的代码长度限制在 80 列。如果⼤于 80 列的话就要分成多⾏编写(其实当前⾼分辨屏幕已经很常见了,基本都是 1080P 起,甚⾄ 4K,所以可以设置更⼤值),并且在低优先级操作符处划分新⾏,操作符放在新⾏之⾸,划分出的新⾏要适当进⾏缩进,⼀般进⾏⼀级缩进即可,如下所⽰:
perm_count_msg.head.len = NO7_TO_STAT_PERM_COUNT_LEN
+ STAT_SIZE_PER_FRAM *sizeof( _UL );
act_task_table[frame_id * STAT_TASK_CHECK_NUMBER + index].occupied
= stat_poi[index].occupied;
if((taskno < max_act_task_number)
&&(n7stat_stat_item_valid(stat_item)))
{
...// program code
}
2、不要把多个语句放到⼀⾏⾥⾯,⼀⾏只写⼀条语句,如下所⽰:
不规范的写法:
a = x+y;
b = x-y;
应该为:
a=x+y;
b=x-y;
3、 不要在⼀⾏⾥⾯防⽌多个赋值语句。
4、if、for、do、while、case、swich、default 等语句单独占⽤⼀⾏。
2.1.3:括号和空格:
1 、括号
代码中⽤到⼤括号“{”和“}”的地⽅,应该把起始⼤括号“{”放到⾏尾,把结束⼤括号“}”放到⾏⾸,如下所⽰:
if(x is true){
we do y
}
上⾯⼤括号“{”和“}”的⽤法适⽤于所有的⾮函数程序块,如 if、switch、for、do、while等,⽐如:
switch(action){
case KOBJ_ADD:
return"add";
case KOBJ_REMOVE:
return"remove";
case KOBJ_CHANGE:
return"change";
default:
return NULL;
}
这⾥要注意函数的起始⼤括号要放置到下⼀⾏的开头!!如下所⽰:
int function(int x)
{
body of function
}
结束的⼤括号“}”要独⾃占⽤⼀⾏,除⾮后⾯跟着同⼀个语句的其它剩余部分,⽐如 do语句中的“while”或者 if 语句中的“else”,如下代码所⽰:
do{
body of do-loop
}while(condition);
和
if(x == y){
..
}else if(x > y){
...
}else{
....
}
当只有⼀个单独的语句的时候就可以不必要加⼤括号了,⽐如:
if(condition)
action();
和
if(condition)
do_this();
else
do_that();
2 、空格
(1)、在⼀些关键字后⾯要添加空格,如:
if、swich、case、for、do、while
但是不要在 sizeof、typedof、alignof 或者__attribute__这些关键字后⾯添加空格,因为这些⼤多数后⾯都会跟着⼩括号,因此看起来像个函数,如:
s =sizeof(struct file);
(2)、如果要定义指针类型,或者函数返回指针类型时,“*”应该放到靠近变量名或者函数名的⼀侧,⽽不是类型名,如:
char*linux_banner;
unsigned long long memparse(char*ptr,char**retptr);
char*match_strdup(substring_t *s);
(3)、⼆元或者三元操作符两侧都要加⼀个空格,例如下⾯所⽰操作符:
=+-<>*/%|&^<=>===!=?:
(4)、⼀元操作符后不要加空格,如:
&*+-~!sizeof typeof alignof __attribute__ defined
(5)、后缀⾃加或者⾃减的⼀元操作符前后都不加空格,如:
++--
(6)、“.”和“->”这两个结构体成员操作符前后不加空格。
(7)、逗号、分号只在后⾯添加空格,如:
int a, b, c;
(8)、注释符“/”和“/”与注释内容之间要添加⼀个空格。
2.2:注释:
2.2.1:注释风格:
注释可以让别⼈⼀看你的代码就明⽩其中的含义和⽤法,但是不要过度注释,不要在注释⾥解释代码是任何运⾏的,⼀般你的注释应该告诉别⼈代码做了什么,⽽不是怎么做的,即结果,⽽⾮过程!注释要放到函数的头部,尽量不要在函数体⾥⾯放置注释,注释的风格应该选择:
/* ……… */
⽽⾮:
//…………
对于多⾏注释,应该选择如下风格:
/*
* 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.
*/
每⼀⾏的开始处都应该放置符号“”,并且所有的⾏的“”要对齐在⼀列上。
2.2.2:⽂件信息注释:
在⽂件开始的地⽅应该对本⽂件做⼀个总体的、概括性的注释,⽐如:版权声明、版本号、作者、⽂件简介、修改⽇志等,如下所⽰的注释:
/*************************************************
Copyright © zuozhongkai Co., Ltd. 1998-2018. All rights reserved.
File name: // ⽂件名
Author: //作者
Version: //版本号
Description: // ⽤于详细说明此程序⽂件完成的主要功能,与其他模块
// 或函数的接⼝,输出值、取值范围、含义及参数间的控
// 制、顺序、独⽴或依赖等关系
Others: // 其它内容的说明
Log: // 修改⽇志,包括修改内容,⽇期,修改⼈等
*************************************************/
2.2.3:函数的注释:
函数需要注释其作⽤,参数的含义以及返回值的含义,注释可以放在函数声明的地⽅,也可以放在函数头,如下:
/*
*@ Description: 函数描述,描述本函数的基本功能
* @param 1 – 参数 1.
* @param 2 – 参数 2
* @return – 返回值
*/
3.标识符命名:
3.1:命名规则:
C 语⾔中的命名有多种风格,有 unix 风格的、有 windows 风格的、还有匈⽛利命名法的等等。因为我们是编写 Linux 代码的,所以要使⽤ unix 风格,⽽ Linux 属于类 unix 系统。unix 命名风格是单词⽤⼩写,然后每个单词⽤下划线“_”连接在⼀起,⽐
如:read_adc1_value(),因此在函数和变量的命名上就要使⽤此种⽅法,这也是 Linux 内核⾥⾯所使⽤的命名⽅法。
注意事项:
1、命名⼀定要清晰!清晰是⾸位,要使⽤完整的单词或者⼤家都知道的缩写,让别⼈⼀读
就懂,避免不必要的误会,⽐如:
int book_number;
int number_of_beautiful_gril;
2、除了常⽤的缩写以外,不要使⽤单词缩写,更不要⽤汉语拼⾳
3、具有互斥意义的变量或者动作相反的函数应该是⽤互斥词组命名,如:
add/remove begin/end create/destroy insert/delete
first/last get/release increment/decrement put/get add/delete
lock/unlock open/close min/max old/new
start/stop next/previous source/target show/hide
send/receive source/destination copy/paste up/down
4、如果是移植的其它的代码,⽐如驱动,命名风格应该和原风格⼀致。
5、不要使⽤单字节命名变量,但是允许使⽤ i,j,k 这样的作为局部循环变量。
3.2 ⽂件命名
⽂件统⼀采⽤⼩写命名。
3.3 变量命名
变量名⼀定要有意义,并且意义准确,单词都采⽤⼩写,⽤下划线“_”连接。⽐如表⽰图书的数量的变量,就可以使⽤如下命名:
int number_of_book;
不要采⽤匈⽛利命名法,尽量避免使⽤全局变量。
3.4 函数命名
和变量命名⼀样。
3.5 宏命名
对于数值等常量宏定义的命名,建议使⽤⼤写,单词之间使⽤下划线“_”连接在⼀起,⽐如:
#define PI_ROUNDED 3.14
4.函数:
函数要简短⽽且漂亮、并且只能完成⼀件事,函数的本地变量数量最好不超过 5-10 个,否则函数就有问题,需要重新构思函数,将其分为更⼩的函数,函数要注意的事项如下:
1 、⼀个函数只能完成⼀个功能
如果⼀个函数实现多个功能的话将会给开发、使⽤和维护带来很⼤的困难。因此,在跟函数⽆关或者关联很弱的代码不要放到函数⾥⾯,否则的话会导致函数职责不明确,难以理解和修改。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论