为了正常的体验网站,请在浏览器设置里面开启Javascript功能!

软件编程规范

2010-06-25 21页 doc 188KB 77阅读

用户头像

is_751722

暂无简介

举报
软件编程规范 软件编程规范 北京和利时系统工程股份有限公司 技 术 文 件 文件名称:秦山一期KIT.PROC.软件编程规范 文件编号: 项目名称:秦山一期电站计算机系统改造软件 项目编号:0316D 物料编码: 受控标识: 第 1 册 共 11 页 共 1 册 版本 状态 拟制 审核 批准 批准日期 修订信息 A 牛玉贞 ...
软件编程规范
软件编程规范 北京和利时系统工程股份有限公司 技 术 文 件 文件名称:秦山一期KIT.PROC.软件编程规范 文件编号: 项目名称:秦山一期电站计算机系统改造软件 项目编号:0316D 物料编码: 受控标识: 第 1 册 共 11 页 共 1 册 版本 状态 拟制 审核 批准 批准日期 修订信息 A 牛玉贞 相关部门会签: 文件发放 部门 主送 阅知 部门 主送 阅知 软件开发部 □ □ ERP事业部 □ □ 硬件开发部 □ □ 交通信息系统事业部 □ □ 技术管理部 □ □ 国际贸易部 □ □ 系统开发部 □ □ 质量部 □ □ 核电项目部 □ □ 财务部 □ □ 生产管理部 □ □ 证券部 □ □ 采购供应部 □ □ 办公室 □ □ 营销部 □ □ 人力资源部 □ □ 工业自动化事业部 □ □ 信息管理部 □ □ 系统集成事业部 □ □ 后勤管理部 □ □ 31. 引言 31.1 目的 31.2 范围 32. 规范 32.1 文件 72.2 版面风格 122.3 标识符命名 142.4 与宏 172.5 代码的可靠性 1. 引言 1.1 目的 本规范的目的在于增加源代码的可读性,减少程序员对代码理解上的偏差,使程序员能够编写出可靠的代码,降低代码维护成本。 1.2 范围 本规范内容涉及范围包括:文件、版面、注释、标识符、变量和结构、函数、宏以及可理解性等。本规范适用于公司开发的所有软件产品。在新软件的编码过程中本规范必须执行。 2. 规范 2.1 文件 2.1.1 头文件的名称一律为小写,格式为“子系统名_文件名.h”。例如:ipf_protocol.h等。 2.1.2 头文件的格式如下: · 注释头,格式参见下面的例子; · 头文件预编译开关开始,格式为: #ifndef 预编译开关 #define 预编译开关 其中预编译开关格式为:“ _文件名_H”,其中文件名一律大写 · 头文件内容; · 头文件预编译开关结束,格式为: #endif 用来和头文件预编译开关的开始对应。 例如:以下为ipf_ip.h头文件的内容: /************************************************************ Copyright (c) Beijing Hollysys Co.,Ltd ALL RIGHTS RESERVED Description: // 用于详细说明此程序文件完成的主要功能 *************************************************************/ #ifndef _IPF_IP_H #define _IPF_IP_H ... <头文件正文> ... #endif 2.1.3 头文件的定义要有层次,禁止交叉引用。 说明:头文件的层次设置为公共模块、私有模块。头文件的引用次序为下层头文件引用上层头文件、私有头文件引用公共头文件,声明结构时尤其要注意,不允许出现交叉引用的情况。 示例:如下定义不符合规范 头文件isdn_a.h /************************************************************ Copyright (c) Beijing Hollysys Co.,Ltd ALL RIGHTS RESERVED Description: 定义配置数据结构 ************************************************************/ #ifndef _ISDN_A_H #define _ISDN_A_H #include “isdn_b.h” typedef struct { ...; ISDN_CONTROL stIsdnControl; ...; }ISDN_ CONFIG; #endif 头文件isdn_b.h /************************************************************ Copyright (c) Beijing Hollysys Co.,Ltd ALL RIGHTS RESERVED Description: 定义控制数据结构 *************************************************************/ #ifndef _ISDN_B_H #define _ISDN_B_H #include “isdn_a.h” typedef struct { ...; ISDN_CONFIG stIsdnConfig; ...; }ISDN_CONTROL; #endif 为了解决上述矛盾,可以将两个结构合并到一个文件中声明。 2.1.4 文件中如果引用系统头文件,必须使用“<“和“>“;如果引用自定义的头文件,必须使用“”“和“”“。 说明:系统头文件是指由编译系统提供的头文件。 示例:如下书写不符合规范。 #include “stdlib.h” #include 应该改作: #include #include “isdn_config.h” 2.1.5 头文件中只能声明变量类型,禁止定义变量。 说明:如果在头文件中定义变量,当有多个源文件引用该头文件时,会出现重复定义的错误。 示例:如下头文件是不规范的。 头文件isdn_a.h /************************************************************ Copyright (c) Beijing Hollysys Co.,Ltd ALL RIGHTS RESERVED Description: 定义配置数据结构 *************************************************************/ #ifndef _ISDN_A_H #define _ISDN_A_H typedef struct { ...; }ISDN_ CONFIG; ISDN_CONFIG g_stIsdnConfig; #endif 结构变量g_stIsdnConfig不能在头文件中定义,只能在源文件中定义。可以在相应的源文件定义后,头文件作如下改动: ISDN_CONFIG g_stIsdnConfig;改为 extern ISDN_CONFIG g_stIsdnConfig; 2.1.6 头文件的声明顺序,应该有层次感。 说明:头文件的声明顺序一般是宏、结构、函数、变量。函数在头文件中声明时开头可以不加“extern” 2.1.7 源文件名称一律小写,格式为:子系统名_文件名.c, 示例:ipf_ pkt.c表示在IPF子系统的包处理文件。 2.1.8 源文件必须加注释头。 源文件注释头格式为: /************************************************************ Copyright (c) Beijing Hollysys Co.,Ltd ALL RIGHTS RESERVED Description: // 用于详细说明此程序文件完成的主要功能 *************************************************************/ 2.2 版面风格 2.2.1 程序块采用缩进风格编写,缩进规定为4个空格(建议不使用TAB符号,因为各个系统TAB符号的空格数不一样)。变量说明之后必须加空行。 说明:由开发工具自动生成的代码例外。 示例:如下例子不符合规范。 void isdn_InitConfig(void) { WORD wConfigNumner; ...; //program code } 应如下书写 void isdn_InitConfig(void) { WORD wConfigNumner; ...; //program code } 2.2.2 不允许把多个短语句写在一行中,一行只写一条语句。 示例:如下例子不符合规范。 wLength = wWidth = 0; 或wLength = 0, wWidth = 0; 应如下书写 wLength = 0; wWidth = 0; 禁止如下写法: int i = j = 0; 或int i = 0,j = 0; 应该写作: int i = 0; int j = 0; 或 int i,j; i = 0; j = 0; 2.2.3 do、while、switch、case、default、if、else、for等语句自占一行,且if、else语句在同一列。 示例1:如下例子不符合规范。 do { ...; //program code } while (pstUser != NULL); 应如下书写: do { ...; //program code } while (pstUser != NULL); 示例2:如下例子不符合规范。 while (pstUser != NULL) { ...; //program code } 应如下书写: while (pstUser != NULL) { ...; //program code } 示例3:如下例子不符合规范。 switch (dwCounter) { case 1: dwCounter++; ...; //program code break; default:break; } 应如下书写: switch (dwCounter) { case 1: dwCounter++; ...; //program code break; default: break; } 示例4:如下例子不符合规范。 if (pstUser == NULL) return; else { ...; //program code } 应如下书写: if (pstUser == NULL) { return; } else { ...; //program code } 示例5:如下例子不符合规范。 for (i = 0;i < 10;i++) { ...; //program code } 应如下书写: for (i = 0;i < 10;i++) { ...; //program code } 2.2.4 函数的开始、结构的定义及循环、判断等语句中的代码都要采用缩进风格。 示例:如下例子不符合规范。 int isdn_Config(void) { ...; // program code return 0; } 应该改为 int isdn_Config(void) { ...; // program code return 0; } 示例:如下例子不符合规范。 typedef struct { WORD wSlot; WORD wPort; }ISDN_CONFIG; 应该改为 typedef struct { WORD wSlot; WORD wPort; }ISDN_CONFIG; 2.2.5 在switch的处理程序块中,case和default语句下的处理语句也要遵从语句缩进要求。 示例: 以下写法是不规范的 switch (wEvent) { case 1: ...; //program code break; } 应该改为: switch (wEvent) { case 1: ...; //program code break; default: break; } 2.2.6 程序块的分界符(大括号'{'和'}')应各独占一行并且位于同一列,同时与引用它们的语句左对齐。 示例:如下例子不符合规范。 if (...) { ... // program code } void isdn_ExampleFun( void ) { ... // program code } 应如下书写。 if (...) { ... // program code } void isdn_ExampleFun( void ) { ...; // program code } 2.2.7 函数头部应进行注释,列出:函数的名称、功能、输入参数、输出参数、返回值等。 示例:编写函数时候按照下面这段注释编写。 /************************************************* Func Name: // 函数名称 Description: // 函数功能的描述 Input: // 输入参数说明 Output: // 对输出参数和函数返回值的说明 *************************************************/ 2.2.8 注释应与其描述的代码相近,对代码的注释应放在其上方或右方(对单条语句的注释)相邻位置,不可放在下面。 示例:如下例子不符合规范。 isdn_Init(); //初始化ISDN任务 应如下书写: //初始化ISDN任务 isdn_Init(); 2.2.9 对有实际含义的变量或者常量的注释,应放在其上方相邻位置或右方。对宏的注释,应放在上面,不可放在其右方或下方。对数据结构的声明(包括数组、结构、类、枚举等),注释应放在其上方相邻位置,不可放在下面;对结构中的每个域的注释放在此域的右方。 示例: 以下写法不规范 #define VOS_ERROR_MSG_ON //错误信息打印输出开关 应改为 // 错误信息打印输出开关 #define VOS_ERROR_MSG_ON 2.2.10 允许使用”//”进行注释 示例:以下注释是允许的 // 根据CFM所存的配置信息更新接口配置信息 void isdn_SetConfigData(void) { ...; //program code } 2.3 标识符命名 2.3.1 局部变量采用大小写混排的匈牙利方式命名,命名格式为前缀+变量名称,其中变量名由一个或一个以上的组成,每个单词首字母大写,其余一律小写。 说明:前缀要表明变量类型。下表为定义变量时候使用的前缀。 类型 前缀 类型名称 BOOLEAN b 布尔型 BYTE by 无符号字符型 WORD w 无符号短整型 DWORD dw 无符号长整型 char c 字符型 short s 短整型 int i 整型 long l 长整型 st 结构类型 un 联合类型 p 指针 pby BYTE的指针 pw WORD的指针 pdw DWORD的指针 pst 结构的指针 pun 联合的指针 pa 数组的指针 pfn 函数指针 pm 消息的指针 pc 字符型的指针 ps 短整型的指针 pi 整型的指针 pl 长整型的指针 pp(根据类型添加其他前缀) 指针的指针 a 数组 aby BYTE数组 aw WORD数组 adw DWORD数组 ast 结构数组 aun 联合数组 afn 函数数组 ac 字符型数组 as 短整型数组 ai 整型数组 al 长整型数组 sz 以null结尾的字符串型 示例: 以下的书写不规范 WORD slot; BYTE *byAccess; DWORD arp_frame_count; 应该写作: WORD wSlot; BYTE *pbyAccess; DWORD dwArpFrameCount; 2.3.2 普通宏的定义使用全大写字母加下划线的方式,结构为:子系统+下划线+宏内容名称。 示例: #define IP_MAX_HWA_LEN 6 #define IP_VER(x) ((x >>4) & 0xF0) 2.3.3 函数的命名为:前缀+下划线+字符串。其中前缀为全小写的子系统名称,字符串由一个或多个单词组成,每个单词首字母大写,其他字母小写。 示例: void vos_MsgCreate(void); void icmp_PktRecv(void); 2.3.4 调试用的编译开关是开头为下划线的全大写字符串,具体格式是:下划线+DEBUG+子系统名称+下划线+名称。 示例:_DEBUG_IPF_IP_PACKET、_DEBUG_TCP_OPTION等。 2.3.5 结构联合类型命名规则为:子系统名称+下划线+结构名称、子系统名称+下划线+联合名称,其中所有字母大写。 示例: typedef struct { ...; }IP_TRACEROUTE; typedef union { ...; }ICMP_PKT; 2.3.6 全局变量命名的具体格式是:前缀+下划线+子系统名+下划线+字符串,其中前缀为小写的“g”,子系统名称全部小写,字符串由一个或多个单词组成,每个单词首字母大写,其他字母小写。 示例:g_icmp_TraceRouteQueue、g_ospf_InterfList等。 2.3.7 消息宏定义采用以下格式:前缀+下划线+字符串+下划线+后缀。其中前缀采用小写的“mm”,字符串标记消息宏的具体含义,由一个或多个单词组成,每个单词首字母大写,其他字母小写,后缀为XXXtoYYY,表示消息的传送方向,XXX表示源子系统名,YYY为目的子系统名,全部用大写字母表示。 示例:mm_AddRoute_BGPtoRTMGT表示从BGP协议发送到路由管理实体的增加一条路由的消息,mm_ShowIpRoute_CLItoRTMGT表示从CLI发送到路由管理子系统的要求显示路由表的消息。 2.4 函数与宏 2.4.1 对函数的返回值要仔细、全面地处理。 说明:对提供返回值的函数,尤其是接口函数,其返回值必须检查。 示例:以下函数是不规范的。 void isdn_SendMessage(void) { ...; //program code vos_MsgPost(...); // 发送消息 } 应该改作 void isdn_SendMessage(void) { INT32 iPost; ...; //program code iPost = vos_MsgPost(...); // 发送消息 if (iPost == VOS_OK) { ...; //处理代码 } else { ...; //处理代码 } } 2.4.2 接口函数的输入参数(尤其是指针和数组下标)、非输入参数的合法性必须检查。 说明:函数的输入主要有两种:一种是参数输入;另一种是非参数输入,包括全局变量、数据文件等,这些参数都需要作检查。 示例:下面函数的实现不符合规范。 RESULT isdn_Receive(NI_CELL *pstCell,SK_BUF *pstSkBuf) { ...; //接收数据代码 return OK; } 应改作以下写法。 RESULT isdn_Receive(NI_CELL *pstCell,SK_BUF *pstSkBuf) { if ((pstCell == NULL) || (pstSkBuf == NULL)) { return FALSE; } ...; //接收数据代码 return OK; } 2.4.3 禁止把函数的参数作为工作变量 说明:需要做改变的参数,应该先用局部变量代之,最后再将该局部变量的内容赋给该参数。 示例:下面函数的实现不符合规范。 BOOLEAN isdn_SumData(WORD wNumber,WORD *pwData, WORD *pwSum) { WORD wCount; if ((pwData == NULL) || (pwSum == NULL)) { return FALSE; } *pwSum = 0; for (wCount = 0; wCount < wNumber; wCount++) { *pwSum += pwData[wCount]; // pwSum成了工作变量,不规范 } return TRUE; } 应改作以下写法。 BOOLEAN isdn_SumData(WORD wNumber,WORD *pwData, WORD *pwSum) { WORD wCount; WORD wSumTemp; if ((pwData == NULL) || (pwSum == NULL)) { return FALSE; } wSumTemp = 0; for (wCount = 0; wCount < wNumber; wCount++) { wSumTemp += pwData[wCount]; } *pwSum = wSumTemp; return TRUE; } 2.4.4 明确函数的返回值,当函数不需要返回值时要定义为void。 示例:如下函数写作不规范 isdn_InitCtrlBlock(void) { ...; //program code } 应改作: void isdn_InitCtrlBlock(void) { ...; //program code } 2.4.5 用宏定义表达式时,要使用完备的括号。 示例:如下定义的宏都存在一定的风险,不符合规范。 #define MAX(a,b) a > b ? a : b #define MAX(a,b) (a > b ? a : b) #define MAX(a,b) (a) > (b) ? (a) : (b) 正确的定义应为: #define MAX(a,b) ((a) > (b) ? (a) : (b)) 2.4.6 使用宏时,不允许参数发生变化。 示例:如下用法导致错误。 #define MAX(a, b) ((a) > (b) ? (a) : (b)) iResult = MAX(iRx++,iTx); 将被预处理器解释为 iResult = ((iRx++) > (iTx) ? (iRx++) : (iTx)); 此时如果输入 iRx = 6; iTx = 5; 代码执行结果iResult = 7,此时iRx为8。 应该改作如下用法: iResult = MAX(iRx,iTx); iRx++; 2.5 代码的可靠性 2.5.1 系统运行之初,要初始化所有本系统的全局变量,禁止未经初始化的全局变量被引用。 说明:使用未初始化的数据,容易使系统进入混乱状态。 示例:以下的全局变量如果没有在系统运行时初始化,在被函数使用时会出错 ISDN_CELL *g_pstIsdnCell[ISDN_MAX_CELL_NUM]; void isdn_ShowChannel(WORD wSlot,WORD wPort) { ISDN_CELL *pstIsdnCell = 0; int i; for (i = 0; i < ISDN_MAX_CELL_NUM;i++) { if (g_stpIsdnCell[i] != NULL) { pstIsdnCell = g_pstIsdnCell[i]; // 如果g_pstIsdnCell没有初始化为空,以下语句会出错 if ((pstIsdnCell->wSlot == wSlot) \ && (pstIsdnCell->wPort == wPort)) break; } } ...; //other program code } 2.5.2 申请内存之后,应该立即检查指针值是否为NULL?(防止使用指针值为NULL的内存) 说明:申请内存时,如果申请失败,应该避免使用该指针。必须使用 if (p == NULL) 或if (p != NULL)进行防错处理。 2.5.3 禁止将未被初始化的内存作为零值使用。 说明:创建的数组或动态申请的内存,其初始值是不确定的,不能当作零处理。 示例:以下代码是不规范的。 void isdn_CheckIe(BYTE *pbyIe,WORD wIeLen) { WORD wTempLen; //wTempLen未初始化,其初始值不一定为0 while(wTempLen < wIeLen) { ...; //other program code wTempLen += 2; } } 应作如下改写: void isdn_CheckIe(BYTE *pbyIe,WORD wIeLen) { WORD wTempLen; wTempLen = 0; while (wTempLen < wIeLen) { ...; //other program code wTempLen += 2; } } 2.5.4 动态内存的申请与释放要配对,防止内存泄漏。 说明:内存泄漏问要高度重视。内存泄漏会引起系统死机或崩溃,一般在系统启动很长一段时间后才发作,不易察觉,一般的测试手段也不到。 2.5.5 在switch的处理程序块中,必须有default语句;并且每个case语句都要有对应的break。 说明:如果一个case下的处理语句需要调用下一个case的处理语句,可以将下一个case的处理语句copy过来。 示例:以下写法是不规范的 switch (wEvent) { case 1: isdn_SendEvent(wEvent); case 2: wEvent++; break; default: break; } 应该改为: switch (wEvent) { case 1: isdn_SendEvent(wEvent); wEvent++; break; case 2: wEvent++; break; default: break; } 2.5.6 不要滥用goto语句。 说明:goto语句会破坏程序的结构性,除非确实需要,不要使用goto语句。 2.5.7 使用显式的数据类型转换,避免让编译器进行隐式的数据类型转换。 说明:使用显示的数据转换一方面增加可读性,有利于代码的维护;另一方面避免隐式的数据类型转换引起的编译告警。 示例: 以下的书写不符合规范 NI_CELL *isdn_Load(void) { NI_CELL *pstNiCell; pstNiCell = vos_malloc(sizeof(NI_CELL)); ...; //program code return pstNiCell; } 应改作: NI_CELL *isdn_Load(void) { NI_CELL *pstNiCell; pstNiCell = (NI_CELL*)vos_malloc(sizeof(NI_CELL)); ...; //program code return pstNiCell; } 2.5.8 不要使用难懂的技巧性很高的语句。 说明:高技巧语句不等于高效率的程序,实际上程序的效率关键在于算法。 示例:如下表达式,考虑不周就可能出问题,也较难理解。 *pbyState ++ += 1; * ++ pbyState += 1; 应分别改为如下。 *pbyState += 1; pbyState ++; // 此二语句功能相当于" * pbyState ++ += 1; " ++ pbyState; *pbyState += 1; // 此二语句功能相当于" * ++ pbyState += 1; " 第 17 页 共 22页 _992860125.doc
/
本文档为【软件编程规范】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。 本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。 网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。

历史搜索

    清空历史搜索