嵌入式Linux C编程规范

C语言编程规范

一、排版格式

1、代码缩进

代码缩进要使用制表符,也就是 TAB 键,不要使用空格键缩进!

  • TAB缩进一般是4个字符,Linux下一般是8个字符,建议统一使用4字符缩进
  • 在 switch 语句中,“swich”和“case”标签应该对齐处于同一列,不需要缩进 case 标签

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;
}

2、代码行

  • 每一行的代码长度限制在 80 列。
  • 不要把多个语句放到一行里面,一行只写一条语句
  • 不要在一行里面防止多个赋值语句
  • if、 for、 do、 while、 case、 swich、 default 等语句单独占用一行

3、括号

非函数程序块:
  • if、 switch、 for、 do、 while等

应该把起始大括号“{”放到行尾,把结束大括号“}”放到行首

Example:

if (x is true) {
    we do y
}

switch (action) {
case KOBJ_ADD:
    return "add";
default:
    return NULL;
}

结束的大括号“}”要独自占用一行,除非后面跟着同一个语句的其它剩余部分,比如 do
语句中的“while”或者 if 语句中的“else”

Example:

do {
body of do-loop
} while (condition); /*跟在“}”后面*/


if (x == y) {
    ..
} else if (x > y) {  /*跟在“}”后面*/
    ...
} else {    /*跟在“}”后面*/
    ....
}

在上面的 if else 条件语句中,所有的分支都只有一行语句,所以可以都不加大括号。但是如果在条件语句中任何一个分支有大于一行语句的时候都必须加上大括号

if (condition) {
    do_this();
    do_that();
} else {
    otherwise();
}

4、空格

(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;

二、注释

1. 注释风格

  1. 注释目的:
  • 注释可以让别人一看你的代码就明白其中的含义和用法
  • 一般你的注释应该告诉别人代码做了什么,而不是怎么做的,即结果,而非过程!
  • 不要过度注释
  • 不要在注释里解释代码是任何运行的
  • 注释要放到函数的头部
  • 尽量不要在函数体里面放置注释
  1. 注释的风格选择

    1. 单行注释

    选择:

    /* ……… */
    

    而非选择:

    //…………
    
    1. 多行注释

    对于多行注释,应该选择如下风格

    /*
    *This is the preferred style for multi-line
    *--------------------
    *with beginning and ending almost-blank lines.
    */
    

2、 文件信息注释

在文件开始的地方应该对本文件做一个总体的、概括性的注释,比如:版权声明、版本号、作者、文件简介、修改日志等,如下所示的注释

/*****************************************************************************
Copyright: 版权,著作权申明
File name: 文件名
Description: 用于详细说明此程序文件完成的主要功能,与其他模块或函数的接口,输出值、取值范围、含义及参数间的控制、顺序、独立或依赖等关系
Author: 作者
Version: 版本
Date: 完成日期
History: 修改历史记录列表, 每条修改记录应包括修改日期、修改者及修改内容简述。
*****************************************************************************/

3、函数注释

函数头部应进行注释,列出:

  • 函数的目的/功能、
  • 输入参数、
  • 输出参数、
  • 返回值、
  • 调用关系(函数、表)等

示例:下面这段函数的注释比较标准,当然,并不局限于此格式,但上述信息建议要包含在内。

/*************************************************
Function: // 函数名称
Description: // 函数功能、性能等的描述
Calls: // 被本函数调用的函数清单
Called By: // 调用本函数的函数清单
Table Accessed: // 被访问的表(此项仅对于牵扯到数据库操作的程序)
Table Updated: // 被修改的表(此项仅对于牵扯到数据库操作的程序)
Input: // 输入参数说明,包括每个参数的作// 用、取值说明及参数间关系。
Output: // 对输出参数的说明。
Return: // 函数返回值的说明
Others: // 其它说明
*************************************************/

三、标识符命名

1、命名规则

1、C语言命名风格分类:
(1). uinx风格: 单词用小写字母,每个单词直接用下划线‘_’分割,所以可以称为下划线法命法

例如: text_mutex

(2). Windows风格: 大小写字母混用,单词连在一起,每个单词首字母大写,也叫帕斯卡命名

例如: UserName

(3). 匈牙利命名: 计算机程序设计中的一种命名规则,用这种方法命名的变量显示了其数据类型,匈牙利命名主要包括三个部分:基本类型、一个或更多的前缀、一个限定词。

匈牙利命名主要包括三个部分:基本类型、一个或更多的前缀、一个限定词。
例如:m_lpszStr, 表示指向一个以0字符结尾的字符串的长指针成员变量。

匈牙利命名法关键是:标识符的名字以一个或者多个小写字母开头作为前缀;前缀之后的是首字母大写的一个单词或多个单词组合,该单词要指明变量的用途

看了在很多地方在介绍完几种命名法之后,都有备注一句:不要使用匈牙利命名法

2、标识符的命名要清晰、明了,有明确含义,同时使用完整的单词或大家基本可以理解的缩写,避免使人产生误解

    int book_number;
    int number_of_beautiful_gril;

3、除了常见的通用缩写以外,不使用单词缩写,不得使用汉语拼音

说明:较短的单词可通过去掉“元音”形成缩写,较长的单词可取单词的头几个字母形成缩写,一些单词有大家公认的缩写,常用单词的缩写必须统一。协议中的单词的缩写与协议保持一致。对于某个系统使用的专用缩写应该在注视或者某处做统一说明

    argument 可缩写为 arg
    buffer 可缩写为 buff
    clock 可缩写为 clk
    command 可缩写为 cmd
    compare 可缩写为 cmp
    configuration 可缩写为 cfg
    device 可缩写为 dev
    error 可缩写为 err
    hexadecimal 可缩写为 hex
    increment 可缩写为 inc、
    initialize 可缩写为 init
    maximum 可缩写为 max
    message 可缩写为 msg
    minimum 可缩写为 min
    parameter 可缩写为 para
    previous 可缩写为 prev
    register 可缩写为 reg
    semaphore 可缩写为 sem
    statistic 可缩写为 stat
    synchronize 可缩写为 sync
    temp 可缩写为 tmp

4、具有互斥意义的变量或者动作相反的函数应该是用互斥词组命名

    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

5、如果是移植的其它的代码,比如驱动,命名风格应该和原风格一致
6、不要使用单字节命名变量,但是允许使用 i, j, k 这样的作为局部循环变量

2、文件命名

文件命名统一采用小写字符

说明:因为不同系统对文件名大小写处理会不同(如MS的DOS、Windows系统不区分大小写,但是Linux系统则区分),所以代码文件命名建议统一采用全小写字母命名

3、变量命名

变量名一定要有意义,并且意义准确,单词都采用小写,用下划线“_”连接。比如表示图书的数量的变量,就可以使用如下命名:

int number_of_book;

不要采用匈牙利命名法,尽量避免使用全局变量。

4、函数命名

和变量命名一样

5、宏命名

对于数值等常量宏定义的命名,建议使用大写,单词之间使用下划线“_”连接在一起

#define PI_ROUNDED 3.14

除了头文件或编译开关等特殊标识定义,宏定义不能使用下划线‘_’开头和结尾

四、函数

1、一个函数只能完成一个功能
2、重复代码提炼成函数
3、不同函数用空行隔开

如果函数需要导出的话,它的 EXPORT*宏应该紧贴在他的结束大括号下

int system_is_up(void)
{
return system_state == SYSTEM_RUNNING;
}
EXPORT_SYMBOL(system_is_up);
4、 函数嵌套不能过深,新增函数最好不超过 4 层

函数嵌套深度指的是函数中的代码控制块(例如: if、 for、 while、 switch 等)之间互相包含的深度

5、对函数的参数做合法性检查

(1)参数名称的命名参照变量命名规范。
(2)为了提高程序的运行效率,减少参数占用的堆栈,传递大结构的参数,一律采用指针或引用方式传递。
(3)为了便于其他程序员识别某个指针参数是入口参数还是出口参数,同时便于编译器检查错误,应该在入口参数前加入const标志。

cmCopyString(const CHAR * c_szSource, CHAR * szDest)

6、对函数的错误返回要做全面的处理
7、源文件范围内定义和声明的函数,除非外部可见,否则都应该用 static 函数

五、变量

变量的命名可以说是我最头疼的事了,经常因为一个变量命名二想半天:

1、一个变量只能有一个功能,不能把一个变量当作多用途
2、不用或者少用全局变量

单个文件内可以使用 static 修饰的全局变量,这可以为文件的私有变量, 全局变量应该是模块的私有数据,不能作用对外的接口,使用 static 类型的定义,可以防止外部文件对本文件的全局变量的非正常访问。直接访问其它模块的私有数据,会增强模块之间的耦合关系

3、防止局部变量和全局变量重名
4、严禁使用未经初始化的变量作为右值
5、明确全局变量的初始化顺序

系统启动阶段,使用全局变量前,要考虑到全局变量该在什么地方初始化!

6、尽量减少不必要的数据类型转换

因为不同编译平台可能导致进行数据类型转换的时候,其数据的意义、转换后的取值等都有可能发生变化

六、宏和变量

1、宏命名

建议使用大写,单词之间使用下划线“_”连接在一起

#define PI_ROUNDED 3.14

2、函数宏的命名

宏的名字一般用大写,但是形如函数的宏,其名字可以用小写,如果能写成内联函数的就不要写成像函数的宏

#define macrofun(a, b, c)    \
    do {                     \
        if (a == 5)          \
            do_this(b, c);   \
} while (0)

3、使用宏的注意事项

1)避免影响控制流程的宏,如下:

#define FOO(x)              \
do {                        \
    if (blah(x) < 0)        \
         return -EBUGGERED; \
} while (0)

2)作为左值的带参数的宏: FOO(x) = y,如果有人把 FOO 变成一个内联函数的话,这种用法就会出错了
3)忘记优先级:使用表达式定义常量的宏必须将表达式置于一对小括号之内

4、常量建议使用 const 定义来代替宏


参考文档 :
《代码整洁之道》
《华为C语言编程规范》
《Linux C代码规范和风格》

发布了10 篇原创文章 · 获赞 5 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/weixin_38091082/article/details/105597629