2019独角兽企业重金招聘Python工程师标准>>>
1. 文件结构
1.1. 版权和版本的声明
版权和版本的声明位于头文件和定义文件的开头(如下图),主要内容有:
(1)版权信息
(2)文件名称,标识符,摘要
(3)当前版本号,作者/修改者,完成日期
(4)版本历史信息
示例1 版权和版本声明
/***********************************************************
* Fenghuo Confidential Proprietary
* (c)NanJing FiberHome Security Company
*
* @file (本文件的文件名)
* @brief (本文件实现的功能的简述)
*
* (本文件实现的功能的详述)
*
* @version 1.1 (版本声明)
* @author (作者)
* @date (文件创建日期,格式: YYYY-MM-DD )
*
* Revision History:
* Author Date(YYYY-MM-DD) Description of Changes
* ------- -------------- --------------------------
*
************************************************************/
1.2. 头文件的结构
头文件由以下三部分内容组成:
(1)头文件开头处的版权和版本声明(如示例1)
(2)预处理块
为了防止头文件被重复引用,使用ifndef/define/endif 结构产生预处理块,具体宏名统一为“_模块名_文件名_H_”。
(3)函数和类结构声明等
说明:
Ø 使用#include <filename.h> 格式来引用标准库的头文件(编译器将从标准库目录开始搜索)。使用#include “filename.h” 格式来引用非标准库的头文件(编译器将从用户的工作目录开始搜索)。先引用非标准库的头文件,再引用标准库的头文件。
Ø 头文件中只存放“声明”而不存放“定义”
1.3. 定义文件的结构
定义文件由以下三部分内容组成:
(1) 定义文件开头处的版权和版本声明
(2) 对一些头文件的引用
(3) 程序的实现体(包括数据和代码)
2. 注释
1. 对于所有变量、常量,如果其命名不是充分自注释的,在声明时都必须加以注释,说明其含义。全局变量要有较详细的注释。
2. 对单个语句行的注释紧靠在其上方,语句较长时要遵循换行规则。
3. 将注释与其上面的代码用空行隔开,注释与所描述内容进行同样的缩排。
4. 对复杂的分支语句(条件分支、循环语句等)要编写注释。
5. 多重嵌套程序块每个子块的结束行右方要加注释以表明该子块的结束。
6. 注释与代码要一致,不再起作用的注释要删除。
7. 中文注释统一采用GB18030方式编写。
8. 注释可参照以下注释示例编写,示例如下:
文件头注释示例
1、 /***********************************************************
2、 * Fenghuo Confidential Proprietary
3、 * (c)NanJing FiberHome Security Company
4、 *
5、 * @file (本文件的文件名)
6、 * @brief (本文件实现的功能的简述)
7、 *
8、 * (本文件实现的功能的详述)
9、 *
10、 * @version 1.1 (版本声明)
11、 * @author (作者)
12、 * @date (文件创建日期,格式: MM/DD/YYYY )
13、 *
14、 * Revision History:
15、 * Author Date(MM/DD/YYYY) Description of Changes
16、 * ------- -------------- --------------------------
17、 *
18、 ************************************************************/
宏定义注释示例
1. /*!
2. * @brief 注释说明
3. */
4. #define MIN 0
结构体注释示例
1. /*!
2. * @struct print
3. * @brief This is a test struct.
4. * Some details about the Test struct
5. */
6. struct print
7. {
8. ……
9. }
类定义注释示例
1. /*!
2. * @class 类名字
3. * @brief 本类的功能:打印错误信息
4. */
5. class CPrintError
6. {
7. ……
8. }
类成员变量定义示例
1. /*!
2. * @var 此处写引用变量名
3. * @brief 此处写成员变量简述
4. * 成员变量详细描述
5. */
6. int m_Var;
成员函数的注释示例
1. /*!
2. * 下面是一个含有两个参数的函数的注释说明(简述)
3. *
4. * @brief 这里写该函数的详述信息
5. * @param a 被测试的变量(param描述参数)
6. * @param s 指向描述测试信息的字符串
7. * @return 测试结果 (return描述返回值)
8. * @retval NULL 空字符串。(说明注释)
9. * @retval !NULL 非空字符串。 (注释)
10. * @note (note描述需要注意的问题)
11. */
12. int testMe(int a,const char *s);
枚举变量的注释示例
1. /*!
2. * @brief 颜色的枚举定义
3. * 该枚举定义了系统中需要用到的颜色\n
4. * 可以使用该枚举作为系统中颜色的标识
5. */
6. enum TEnum
7. {
8. RED, /*!< 枚举,标识红色 */
9. BLUE, /*!< 枚举,标志蓝色 */
10. YELLOW /*!< 枚举,标志黄色. */
}enumVar;
3. 程序的版式
1. 程序块要采用缩进风格编写,同一个源文件缩进的空格数要一致。统一使用4个空格。
2. 相对独立的程序块之间、程序块与变量说明之间要加空行。
3. 界符‘{’和‘}’应独占一行并且位于同一列,同时与引用它们的语句左对齐。{ }之内的代码块在‘{’右边数格处左对齐。嵌套的程序块通过缩进区分等级。
4. 一行代码只做一件事情,如只定义一个变量,或只写一条语句。这样的代码容易阅读,并且方便于写注释。
5. 较长的语句(>80字符)要分成多行书写,长表达式要在低优先级操作符处划分新行,操作符放在新行之首,划分出的新行要进行适当的缩进,使排版整齐,语句可读。
参考示例:
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;
act_task_table[taskno].duration_true_or_false
= SYS_get_sccp_statistic_state( stat_item );
report_or_not_flag = ((taskno < MAX_ACT_TASK_NUMBER)
&& (n7stat_stat_item_valid (stat_item))
&& (act_task_table[taskno].result_data != 0));
6. if、for、do、while、case、switch、default等语句自占一行,且if、for、do、while等语句的执行语句部分无论多少都要加括号{},哪怕只有一个return语句。
7. 函数名之后不要留空格,紧跟左括号‘(’,以与关键字区别。
8. ‘(’向后紧跟,‘)’、‘,’、‘;’向前紧跟,紧跟处不留空格。
9. ‘,’之后要留空格,如Function(x, y, z)。如果‘;’不是一行的结束符号,其后要留空格,如for (initialization; condition; update)。
10. 比较操作符, 赋值操作符"="、 "+=",算术操作符"+"、"%",逻辑操作符"&&"、"&",位域操作符"<<"、"^"等双目操作符的前后加空格。
11. "!"、"~"、"++"、"--"、"&"(地址运算符)等单目操作符前后不加空格。
12. 像“[]”、“.”、“->”这类操作符前后不加空格。
13. 对于表达式比较长的for 语句和if 语句,为了紧凑起见可以适当地去掉一些空格,如for (i=0; i<10; i++)和if ((a<=b) && (c<=d))
4. 命名规则
1. 标识符的命名要清晰、明了,有明确含义,同时使用完整的单词或大家基本可以理解的缩写,避免使人产生误解。
2. 文件名采用“模块名_子模块名_类名”。
3. 类、结构体、函数名采用大写字母开头的单词组合而成(不加下划线,即采用骆驼命名法)。
4. 常量和宏定义采用字母全部大写,可用下划线分割单词。
5. 对变量命名,最好能表明具体含义、变量类型。变量和参数用小写字母开头表示类型,后跟大写字母开头的单词组合而成。
公有成员变量加“m_”前缀,保护及私有成员变量加“_”前缀,全局变量加“g_”前缀,静态变量加前缀“s_”(表示static)。在变量名前加入前缀以标识其类型。 (类型前缀如下图:)
前 缀 | 类 型 |
a | 数组 (Array) |
b | 布尔值 (Boolean) |
by | 字节 (Byte) |
c | 有符号字符 (Char) |
cb | 符号字符 (Char Byte,没有多少人用) |
cr | 颜色参考值 (ColorRef) |
cx ,cy | 坐标差(长度 ShortInt) |
dw | Double Word |
fn | 函数 |
h | Handle(句柄) |
i | 整型 |
l | 长整型 (Long Int) |
lp | Long Pointer |
m_ | 类的成员 |
n | 短整型 (Short Int) |
np | Near Pointer |
p | Pointer |
s | 字符串型 |
sz | 以null做结尾的字符串型 (String with Zero End) |
w | Word |
vec | vector |
list | list |
que | queue |
mmap | multimap |
map | map |
set | set |
st | struct |
参考示例:
int m_iTmpValue;(小写字母i开头表示类型,后跟大写字母开头的单词组合)
6. 尽量用const替代宏定义常量。
7. 不要用数字或较奇怪的字符来定义标识符。
参考示例:如下命名,使人产生疑惑。
#define _EXAMPLE_0_TEST_
#define _EXAMPLE_1_TEST_
void set_sls00( BYTE sls );
8. 避免名字中出现数字编号,如Value1,Value2 等。
9. 代码行中不要使用魔鬼数字。必须用有意义的枚举或宏来代替。
10. 单字符的如i,j,k,m,n,x,y,z 等,只能用做函数内的局部变量,并且具有不超过5行的生命周期。
11. 程序中不要出现仅靠大小写区分的相似的标识符。
12. 程序中不要出现标识符完全相同的局部变量和全局变量,尽管两者的作用域不同而不会发生语法错误,但会使人误解。
13. 在同一软件产品内,应规划好接口部分标识符(变量、结构、函数及常量)的命名,防止编译、链接时产生冲突。
说明:对接口部分的标识符前面可加上“模块”标识等以增加唯一性。
5. 表达式和基本语句
1. 不要编写太复杂的复合表达式。
参考示例:
i = a >= b && c < d && c + f <= g + h ;
2. 不要有多用途的复合表达式。
参考示例:
d = (a = b + c) + r ;
3. 不要把程序中的复合表达式与“真正的数学表达式”混淆。
参考示例:
if (a < b < c) // a < b < c 是数学表达式而不是程序表达式
并不表示
if ((a<b) && (b<c))
而是成了令人费解的
if ( (a<b)<c )
4. 不可将布尔变量直接与TRUE、FALSE 或者1、0 进行比较。
参考示例:
if (flag) // 表示flag 为真
if (!flag) // 表示flag 为假
5. 应当将整型变量用“==”或“!=”直接与0 比较。
6. 不要将浮点变量用“=”或“!=”与任何数字比较
千万要留意,无论是float 还是double 类型的变量,都有精度限制。所以一定要避免将浮点变量用“==”或“!=”与数字比较,应该设法转化成“>=”或“<=”形式。
假设浮点变量的名字为x,应当将
if (x == 0.0) // 隐含错误的比较
转化为
if ((x>=-EPSINON) && (x<=EPSINON))
7. 应当将指针变量用“==”或“!=”与NULL比较
8. 在比较变量与常量时特意把常量放在左边,可防止将“==”写成“=”。
9. 在多重循环中,如果有可能,应当将最长的循环放在最内层,最短的循环放在最外层,以减少CPU 跨切循环层的次数。
示例4-4(b)的效率比示例4-4(a)的高。
10. 如果循环体内存在逻辑判断,并且循环次数很大,宜将逻辑判断移到循环体的外面。示例4-4(c)的程序比示例4-4(d)多执行了N-1次逻辑判断。并且由于前者老要进行逻辑判断,打断了循环“流水线”作业,使得编译器不能对循环进行优化处理,降低了效率。如果N 非常大,最好采用示例4-4(d)的写法,可以提高效率。如果N 非常小,两者效率差别并不明显,采用示例4-4(c)的写法比较好,因为程序更加简洁。
11. for 语句的循环控制变量的取值采用“半开半闭区间”写法。
12. 不可在for 循环体内修改循环变量,防止for 循环失去控制。
13. 每个case 语句的结尾不要忘了加break。
14.不要忘记最后那个default 分支。即使程序真的不需要default 处理。
15. 尽量不使用goto语句。
16. 注意运算符的优先级,用括号明确表达式的操作顺序,避免使用默认优先级。
6. 函数
1. 函数名应准确描述函数的功能,使用动词或动宾词组为执行某操作的函数命名。
2. 检查函数参数输入的有效性,注意参数顺序,输入参数在前,输出参数在后。。
3. 如果参数是指针或引用,且仅作输入用,则应在类型前加const,以防止该指针在函数体内被修改。
4. 如果输入参数以值传递的方式传递对象,则宜改用“const &”方式来传递,这样可以省去临时对象的构造和析构过程,从而提高效率。
5. 在调用函数填写参数时,应尽量减少没有必要的默认数据类型转换或强制数据类型转换。
6. 不要将正常值和错误标志混在一起返回。正常值用输出参数获得,而错误标志用return 语句返回。
7. 有时候函数原本不需要返回值,但为了增加灵活性如支持链式表达,可以附加返回值。
8. 一个函数仅完成一件功能,函数的规模尽量限制在200行以内,不包括注释和空格行。
9. 如果多段代码重复做同一件事情,应考虑合并为一个函数。
10. 当一个函数中对较长变量(一般是结构的成员)有较多引用时,可以用一个意义相当的宏代替。
参考示例:
# define pSOCKDATA TheReceiveBuffer[FirstScoket].byDataPtr
7. 内存管理
1. 过程/函数中分配的内存,在过程/函数退出之前要释放。
2. 过程/函数中申请的(为打开文件而使用的)文件句柄,在过程/函数退出之前要关闭。
3. 系统运行之初,要初始化有关变量及运行环境,防止未经初始化的变量被引用。
4. 谨防内存操作越界,时刻注意表达式是否会上溢、下溢。
5. 使用变量时要注意其边界值的情况。
参考示例:
char chr = 127;
int sum = 200;
chr += 1; // 127为chr的边界值,再加1将使chr上溢到-128,而不是128。
6. 使用堆分配的内存要注意malloc/free、new/delete的配对,释放后的内存指针要及时设置为NULL。