AliOS Things Coding Style Guide - Shaofa/AliOS-Things-Certification-Manual GitHub Wiki
- 朴实,避免晦涩语法
- 严谨,逻辑反复思考
- 简约,命名简洁、代码精炼
- 性能,通过算法、编译器、硬件进行优化
-
原则:
整个工程按照功能模块划分子目录,每个子目录再划分头文件和源文件目录,以便架构清晰、易懂。
-
示例:
在比较复杂的项目时,建议目录结构如下:
在项目相对简单时,建议目录结构如下:
-
原则:
目录的命名能准确描述模块的基本功能,建议用小写字母且不含下划线、点等特殊符号;
目录必须放于相包含的父目录之下,并需要明确与其他目录间的耦合性。
-
示例:
- kernel:系统内核部分;
- libs:依赖库;
- mqtt:mqtt协议库;
- external/mbedtls:位于第三方库目录的mbedtls库
-
原则:
新添加组件往往依赖于系统原有组件,必须以最小耦合的方式明确所直接依赖的组件。
-
示例:
略
-
原则:
头文件命名能准确描述文件所包含的模块内容,达到通俗、易懂的目的。
-
示例:
略
-
原则:
项目内的所有头文件(除引入的第三方库)版权声明一致,并且在文件内顶格注释。
-
示例:
如AliOS版权声明如下:
/* * Copyright (C) 2015-2017 Alibaba Group Holding Limited */
-
原则:
项目内的所有头文件采用#define宏防止多重包含,命名格式为:
XXX_FILENAME_H
注:为了保证宏定义的惟一性,建议“XXX”命名为头文件目录名、路径名或有意义的其他符号(如“k”: kernel)。
-
示例:
如下图,在版权声明后空一行,且在“#endif”后空一行且添加注释(注释内容两边各留一个空格且采用“/* */”格式)。
/* * Copyright (C) 2015-2017 Alibaba Group Holding Limited */ #ifndef K_ERR_H #define K_ERR_H #endif /* K_ERR_H */
-
原则:
系统头文件和第三方库通过“<.h>”方式引用,其他文件通过“.h”引用。
-
示例:
略
-
原则:
由于C++编译器在编译时与C编译器命名不同,为了保证C++代码能够正确调用C接口, 建议在C语言接口声明时采用extern的方式指示编译器按C语言去编译。
-
示例:
如下图,在extern的声明代码上下各添加一行空行。
/* * Copyright (C) 2015-2017 Alibaba Group Holding Limited */ #ifndef K_ERR_H #define K_ERR_H #ifdef __cplusplus extern "C" { #endif #ifdef __cplusplus } #endif #endif /* K_ERR_H */
-
原则:
源文件命名能准确描述文件所包含的模块内容,达到通俗、易懂的目的。
-
示例:
略
-
原则:
项目内的所有头文件(除引入的第三方库)版权声明一致,并且在文件内顶格注释。
-
示例:
如AliOS版权声明如下:
/* * Copyright (C) 2015-2017 Alibaba Group Holding Limited */
-
原则:
在源文件中引入头文件时采用如下顺序:C库、C++库、其他第三方库、项目内头文件, 同一类型的头文件采用字母顺序排列,避免引入冗余头文件。
-
示例:
略
-
原则:
源文件中函数的定义顺序严格按照头文件中声明的顺序排列,且内部函数添加static关键字,比较短的函数还需添加inline关键字。 对外函数必须进行参数检查,内部函数不做检查参数要求。返回值必须类型匹配。
-
示例:
略
- 统一,相同含义的单词、命名方式项目内统一。
- 准确,采用计算机领域常用单词。
- 风格,采用字符加下划线的方式(不使用驼峰风格)
-
原则:
建议采用计算机领域常用缩写以便清晰表达含义,相关缩写可参考。
-
示例:
略
-
原则:
数据结构类型以“_t”结尾,枚举变量类型以“_e”结尾,回调函数类型以“_cb”结尾;或所有类型以“_t”作为后缀。字符均小写。
-
示例:
typedef int (*xxx0_cb)(...); typedef struct { ... } xxx1_t; typedef struct xxx2_s { struct xxx2_s *x; ... } xxx2_t; typedef enum { ... } xxx3_e;
-
原则:
全局变量以“g_”作为前缀,内部变量尽量简洁,每个变量的字段不超过5个,字符均小写。
-
示例:
略
-
原则:
常量命名各字段必须大写,且字段数不超过5个。
-
示例:
略
-
原则:
对外的函数建议采用统一前缀,如“aos_”,源文件内部函数建议以“_”作为前缀,且命名字段数不超过5个,字符均小写。
-
示例:
略
-
原则:
枚举命名各字段必须大写,且字段数
不超过5个
。 -
示例:
略
-
原则:
宏命名各字段必须大写,且字段数
不超过5个
。 -
示例:
略
-
原则:
统一采用“/**/”方式注释,且注释内容左右各留一个空格,如“/* message */”;注释必须使用英文。
-
示例:
略
-
原则:
对外接口按doxgen要求的格式书写,且注释和函数定义间不留空行; 对内接口在需要时添加注释,注释位于定义前。
-
示例:
/** * This function will initialize a work * * @param[in] work the work to be initialized * @param[in] fn the call back function to run * @param[in] arg the paraments of the function * @param[in] dly ms to delay before run * @return the operation status, 0 is OK, others is error */ int aos_work_init(aos_work_t *work, void (*fn)(void *), void *arg, int dly);
-
原则:
注释在变量定义后,在仅有一个需要注释的变量时与分号之间只留一个空格; 若多行变量定义均需注释,则最长变量定义留一个空格,其他注释与其对齐。
-
示例:
int func1(void) { int ret; /* return value */ ... return 0; } int func2(void) { int ret; /* return value */ int value; /* value */ ... return 0; }
-
原则:
注释在宏定义后,在仅有一个需要注释的宏时与分号之间只留一个空格; 若多行宏定义均需注释,则最长宏定义后留一个空格,其他注释与其对齐。
-
示例:
#define TASK_RUNNING 0 #define TASK_STOPPED 1 #define TASK_SLEEP 2
-
原则:
所有的缩进必须使用空格(除makefile外不允许使用tab),且以
四个空格
为单位进行缩进。 嵌套的编译条件判断顶格写,且需要在“#endif”后的注释中备注属于哪个判断条件。 -
示例:
#ifdef XXX int func1(void) { ... #ifdef XX func(); #endif /* XX */ ... } #endif /* XXX */
-
原则:
在所有需要空行的地方仅空一行,如版权声明与代码之间,不同类型的头文件引用之间,函数定义之间等。
-
示例:
略
-
原则:
全局变量的声明必须放在相关头文件中,且单个声明的类型和变量之间留一个空格,多个声明时按最长的留一个空格对齐。
-
示例:
extern int g_x_x; /* ... */ extern int g_xx_xx; /* ... */ extern long g_xxx_xxx; /* ... */ extern char *g_xxxx_xxxx; /* ... */
-
原则:
全局变量的定义必须放在相关的源文件中,且在头文件和函数定义之间; 局部变量的定义必须放在函数作用域的最开始处; 变量定义的类型和变量之间(或者“*”)留一个空格,当有多个变量时按照最长原则对齐。
-
示例:
int tmp = 0; int tmp1 =0; long tmp2 = 0; int tmp3 = 0; char *tmp4 = NULL; int g_x_x; /* ... */ int g_xx_xx; /* ... */ long g_xxx_xxx; /* ... */ char *g_xxxx_xxxx; /* ... */
注:上图中描述了四种情况下的对齐方式
-
原则:
在头文件中引用其他项目内头文件的结构体定义时采用extern进行声明,不引入相关头文件。
-
示例:
略
-
原则:
结构体定义放在相关头文件中,并且在函数声明前,结构体定义前后需要各空一行。
-
示例:
略
-
原则:
对外函数的声明必须放在头文件中,且在头文件中按照关联性排序; 当每行超过
80列
时需将参数移到下一行且与上一行参数首字符对齐; 函数内紧邻左右大括号的参数不需要空格,但参数之间需要留一个空格; 仅一个函数时,返回类型与函数定义之间空一格,当多个关联函数时,返回最长的类型与函数定义之间空一格,其他关联函数首字符与其对齐。 对内声明的参数除放在源文件中外,其他与对外声明的函数保持一致。 -
示例:
命名顺序、空格、空行、参数换行请参考下图。
int xxx_xxx_func1(void); int xxx_xxx_func2(void); int xxx_xxx_func3(...); int xxx_xxx_func4(...); void xxx_xxx_func5(...); void *xxx_xxx_func6(...);
-
原则:
函数的定义原则上在源文件中实现,且其定义的顺序与声明保持一致; 在函数定义时,需要将大括号另起一行,且代码逻辑紧邻大括号后一行; 函数之前留一空行。
-
示例:
int xxx_func1(void)
{
return 0;
}
int xxx_func2(void)
{
return 0
}
int xxx_func3(void)
{
return 0;
}
-
原则:
函数调用风格与定义基本相同,在超过
80列
时按照相同的规范处理; 需要对函数调用的返回值进行判断,且判断语句与上一条语句之间不留空行。 -
示例:
int xxx_func(void) { int ret; ret = xxx_func1(...); if (ret != 0) { ... return ret; } return 0; }
-
原则:
条件判断必须明确,如“if (var)”形式应该写为“if (var != 0)”; 指针是否为空时必须与NULL进行对比(不建议用0),整型返回值可通过与1/0进行对比。
-
示例:
if (var != 0) { return -1; } if (ret != 0) { ... return -2; }
-
原则:
风格与条件判断语句类似。
-
示例:
for (i = 0; i < 100; i++) { ... } while (ret == 1) { ... } do { ... } while(ret != 1);