跳过正文

代码风格

1、C
#

1.1 注释
#

按照 C 语言风格,使用/* */添加注释,不使用//

.c文件头注释

/*
 *  Copyright (c) 2022, The xxx project authors. All Rights Reserved.
 *  SPDX-License-Identifier: MIT
 *
 *  First Created :
 *  Author	      : nanche
 *  Description   : 文件级注释应该广泛/简单地描述文件的内容,以及抽象是如何相关的
 */

.h文件头注释

/*
 * Copyright (c) %YEAR%, The xxx project authors. All Rights Reserved.
 * SPDX-License-Identifier: MIT
 *
 * First Created : %DATE%
 * Author        : nanche <%MAIL%>
 * Description   :
 */

#ifndef %GUARD%
#define %GUARD%


#endif

函数注释

参数命名写清楚含义,前面可以加 IN/OUT,不需要在函数注释中添加过多重复信息。

注释说明代码做了什么,而不是如何做

/*
 * 函数功能、实现大致思路、需要注意的点
 * 需要特别注意的参数
 * 函数是否分配了必须由调用者释放的空间.
 * 参数是否可以为空指针.
 * 是否存在函数使用上的性能隐患.
 */

TODO 注释

/*
 * TODO:
 */

1.2 C 工程结构
#

├── build.sh
├── LICENSE
├── Makefile
├── README
├── .gitignore
├── 3rdparty/
├── build/
   ├── debug/
   └── release/
├── doc/
├── examples/
├── src/
   ├── main.c
   ├── include/
       └── type_pub.h
   ├── module_1/
      ├── cps.c
      └── cps.h
   └── module_2/
├── scripts/
└── test/
  • 公共头文件放在 src/include 目录下,文件结尾加 pub

  • 3rdparty/ 下存放的工程中用到的第三方库和第三方源码。第三方库尽量不要直接把静态连接库直接放到git仓库中,应该另外提供链接以便下载,或者提供文档说明库的名称和版本自行安装下载,或者提供git仓库自行编译。第三方源码一般为开源的,只提供git链接。

  • TODO:日志文件/文件夹

1.3 公共头文件
#

类型定义 type_pub.h

#include <stdint.h>

#ifnedf IN
#define IN
#endif

#ifnedf OUT
#define OUT
#endif

#ifnedf INOUT
#define INOUT
#endif

1.4 命名规范
#

变量命名:Linux 标准风格,小写字母加下划线

宏命名:模块名_功能名

复杂数据类型:全部为大写字母,结尾用 S 表示结构体,U 表示联合体,E 表示枚举

typedef struct PPP_CB
{
    uint32_t c_p;
    ...
}PPP_CB_S;

typedef union SNMP_CMD
{
    uint8_t cmd;
    ...
}SNMP_CMD_U;

typedef enum SNMP_ERR
{
   	err_1;
    err_2;
}SNMP_ERR_E;

1.5 其他规范
#

Linux 下括号 {}的使用原则如下:

  • if、else、for、do、while、switch、case、default 等语句各自占一行,其后语句一律用{}括起来,哪怕只有一行
  • 大括号自己独占一行

Linux 空格的使用方式主要取决于它是函数还是关键字。大多数关键字后要加空格:

if switch, case, for, do, while

但是不要在 sizeof、typeof、alignof 这些关键字后加空格:

s = sizeof(struct file)

不要在小括号里的表达式两边加空格。

当声明指针类型或者返回指针类型的函数时, * 的首选使用方式是使之靠近变量名或者函数名,而不是靠近类型名:

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

二元运算符两边加空格,一元运算符不加空格(二元运算符:有两个操作数,如 a + b)


对于 switch/case 语句,Linux 建议 switch 和 case 对齐,例如:

switch(suffix){
case 'G':
case 'g':
	mem <<= 30;
	break;
default:
	break;
}

如果一个数据结构,在创建和销毁它的单线程执行环境之外可见,那它必须要有一个引用计数器。内核里没有垃圾收集,这意味着你必须要记录对这个数据结构的使用情况。

如果另一个线程中可以拿到该数据结构,但这个数据结构没有引用计数器,那这就是一个 bug。


定义几个相关的常量时,枚举比宏定义更好。

typeof(x) 可以获得 x 的类型

C99 已经支持 __func__ 宏,可以得到当前函数名称。


goto 语句

用不用 goto 语句一直是一个著名的争议话题,Linux 内核源代码中对 goto 的应用非常广泛,但一般只用在错误处理中:

if(register_a() != 0)
	goto err;
if(register_b() != 0)
	goto err1;
...

err1:
	unregister_b();
err:
	return ret;

需要保证在错误处理时注销、资源释放等,与正常的注册、申请资源释放顺序相反。


2、Python
#

文件头注释
#

# -*- coding: utf-8 -*-

"""
Copyright (c) 2022, The xxx project authors. All Rights Reserved.
SPDX-License-Identifier: MIT

First Created :
Last  Updated :
Author	      : nanche
Description   :
"""