C语言编程规范.docx
- 文档编号:29089587
- 上传时间:2023-07-20
- 格式:DOCX
- 页数:21
- 大小:37.38KB
C语言编程规范.docx
《C语言编程规范.docx》由会员分享,可在线阅读,更多相关《C语言编程规范.docx(21页珍藏版)》请在冰豆网上搜索。
C语言编程规范
C语言编程规范
斐讯数据通信有限公司
文档更新记录
日期
更新人
版本
备注
2010-4-13
韩冲
V0.0.1
创建文档
目录
1引言4
1.1编写目的4
1.2适用范围4
1.3缩写和术语4
2命名规则4
3文件结构7
3.1头文件的结构7
3.2源文件的结构7
4程序板式7
4.1空行7
4.2代码行7
4.3代码行内的空格8
4.4对齐8
4.5长行拆分8
4.6修饰符的位置8
4.7注释8
5语言编写9
5.1表达式9
5.2声明和定义9
5.3整数数据类型及操作10
5.4字符操作10
5.5浮点型10
5.6类型转换10
5.7常量11
5.8指针11
5.9数组11
5.10函数与宏11
5.11控制语句12
5.12内存分配13
5.13错误处理13
5.14断言13
5.15预处理器指令14
5.16打印语句14
6附件14
6.1头文件模版14
6.2源文件模版14
6.3函数头模版15
1引言
1.1编写目的
本文档的目的是为企业使用C语言进行软件开发提供一个使用规范指南,包括:
●命名规则
●文件的组织
●程序风格样式
●编程规则和建议
本编程规范中的规则必须遵守,而建议则希望被遵守。
1.2适用范围
以模块、子模块为单位,本编码规范适用范围规定如下:
●重新开发的完全自研模块,应遵守本编码规范
●优化改进的完全自研模块,应遵守本编码规范
●移植第三方代码的模块(新编代码比重较小),优先采用第三方代码的风格,以保持整个模块的风格一致
●改造第三方代码的模块(新编代码比重较大),新编写的子模块优先采用本编码规范
●基于自动生成的代码框架进行开发的模块,优先采用本编码规范。
●凡是不采用本编码规范的模块和子模块,应提出申请并获得项目组的同意。
1.3缩写和术语
标识符:
指C中的一个变量、常量、函数或类型。
在本文档中它与“名称”同义。
定义:
变量或常量的定义是指编译器为其分配的内存。
函数的定义是指函数体的实现。
声明:
指一些实体对编译器的声明所在的位置,如函数原型、类型(由typedef定义)、变量和常量。
宏:
指由#define语句定义的代替一个文本串的名字。
当该名字在源程序中出现时,预处理器用对应文本串代替它。
固有数据类型(或预定义或基本数据类型):
由语言本身定义的数据类型,如int。
用户定义数据类型:
编程人员用struct、union、enum或typedef定义的数据类型。
范围:
标识符的范围是指其可见的环境。
环境在这里指可以使用该标识符的函数或程序块。
全局:
使用范围没有限制。
文件级局部:
使用范围局限在一个文件中。
函数级局部:
使用范围局限在一个函数中。
头文件:
C程序中用于保存程序的声明的文件称为头文件;头文件以”.h”为后缀。
源文件:
C程序中用于保存程序的实现的文件称为源文件,源文件以”.c”为后缀。
2命名规则
类别
规则编号
规则内容
通用规则
规则2.1
-所有模块、函数、变量、宏的名称均由字母、数字和下划线组成;
-名称的开始或最后不得使用下划线”_”,(使用操作系统或第三方软件产生的标识符、或为操作系统或第三方软件定义有特殊要求的标识符,确实无法满足本规则的,可例外);
-名称中不得包含两个连续的下划线;
-数字不能出现在名称的开头;
-名称总长度不得超过48字符;
-所有的名称均应具有实际含义、体现用途,不得包含那些不被普遍接受的缩略语。
变量
规则2.2
-变量命名借鉴匈牙利命名法,并在该命名法基础上适当改进。
-变量采用“tXxxYyy”,t表示该变量的类型,XxxYyy表示对该变量的描述,多个单词之间使用首字母大写进行分割。
-如果是某种指针类型的变量,则在类型之前加“p”,变成“ptXxxYyy”
-如果是某种指向指针的指针类型的变量,则在类型之前加“pp”,变成“pptXxxYyy”
-如果是一维数组,则在类型之前加“a”,变为 “atXxxYyy”,二维数组则在类型之前加“aa”,变为 “aatXxxYyy”
-如果是全局变量,则在变量最前面用“g_”标识,如:
“g_tXxxYyy”,“g_ptXxxYyy”,“g_atXxxYyy”
-Statics_tXxx
-静态全局变量:
s_tXxx
-数据类型,及其对应的缩写如下:
数据类型标准c数据类型简写
inti
charc
shorts
longl
unsignedcharuc
unsignedshortus
unsignedlongul
longb
char*sz/*字符串*/
char*pc/*字节流*/
unsignedintui
floatfl
doubledl
voidv
void*pv
结构st
联合un
枚举en
函数指针类型f
模块/子系统
规则2.3
-模块/子系统名以字母、数字和下划线组合而成;
-模块/子系统名的定义及使用应在各项目相关文档中说明并在随后的设计过程中遵守。
函数
规则2.4
-函数名以字母、数字和下划线组合而成;
-函数名统一用小写字母,使用“_”连接各部分;
-函数名以“模块名_”开始,其中子系统名和模块名都使用小写;
-中断服务程序末尾加“_isr”
宏和常量
规则2.5
-宏名和常量由大写字母、数字或下划线组成,以下划线作为区分语义各部分的分割符。
-消息ID的宏命名,按照格式“模块_XXX_XXX_EVT”命名。
文件
规则2.6
-文件名必须以小写字母、数字和下划线组合而成;
-文件名不得超过48个字符(不含扩展名),扩展名不超过3个字符。
下划线作为区分语义各部分的分割符。
类型
规则2.7
-类型的命名由大写字母、数字和下划线组成,使用下划线连接个语义部分。
-结构类型的命名以“子系统_模块_”开始,以“_T”结束。
消息对应的消息体结构类型,直接在消息ID名称后面添加“_T”。
-联合类型的命名以“子系统_模块_”开始,以“_U”结束。
消息对应的消息体联合类型,直接在消息ID名称后面添加“_U”。
-枚举类型的命名以“子系统_模块_”开始,以“_E”结束。
消息对应的消息体枚举类型,直接在消息ID名称后面添加“_E”。
3文件结构
3.1头文件的结构
●规则3.1.1:
头文件中的不同类型声明按照以下顺序排列:
头文件模板具体见附件章节中的“头文件模板”。
●规则3.1.2:
头文件大小不应该超过1000有效代码行
3.2源文件的结构
●规则3.2.1:
源文件按照以下顺序组织:
源文件的模板具体见附件章节中的“源文件模板”。
●规则3.2.2:
源文件的大小不超过3000有效代码行:
4程序板式
版式虽然不会影响程序的功能,但会影响可读性。
程序的版式追求清晰、美观,是程序风格的重要构成因素。
4.1空行
空行起着分隔程序段落的作用。
空行得体(不过多也不过少)将使程序的布局更加清晰。
●建议4.1.1:
在相对独立的程序块之间、变量说明之后、每个函数定义结束之后都要加一行空行。
●建议4.1.2:
在一个函数体内,逻揖上密切相关的语句之间不加空行,其它地方应加空行分隔。
4.2代码行
●规则4.2.1:
每行最多包含一个声明。
●规则4.2.2:
if、for、while、do等语句自占一行,执行语句不得紧跟其后。
不论执行语句有多少都要加”{}”。
●建议4.2.1:
变量的声明与初始化应该尽可能同时进行。
●建议4.2.2:
用统一的格式书写预处理指令。
4.3代码行内的空格
●规则4.3.1:
关键字之后要留空格。
const、case等关键字之后至少要留一个空格;if、for、while等关键字之后应留一个空格再跟左括号”(”。
●规则4.3.2:
赋值操作符、比较操作符、算术操作符、逻辑操作符、位域操作符,如“=“、”+=““>=“、”<=“、”+”、”*”、”%”、”&&”、”||“、”<<“,”^”等二元操作符的前后必须加空格。
●规则4.3.3:
一元操作符”!
”、”~”、”++”、”--””&(地址运算符)”等与操作数之间不得加空格。
●规则4.3.4:
在”[]”与数组名之间及”.”、”->“操作符的前后不得加空格。
●建议4.3.1:
函数名之后不要留空格,紧跟左括号”(”。
●建议4.3.2:
”(”向后紧跟;”)”、”,”、”;”向前紧跟,紧跟处不留空格。
●建议4.3.3:
”,”之后要留空格。
如果”;”不是一行的结束符号,其后要留空格。
●建议4.3.5:
三元操作符周围要有空格。
4.4对齐
●规则4.4.1:
程序的分界符”{“和”}”应独占一行并且位于同一列。
●规则4.4.2:
{}之内的代码块在”{“右边4格处左对齐。
●规则4.4.3:
程序左边界以4空格的倍数对齐,禁止使用Tab键。
4.5长行拆分
●规则4.5.1:
代码行一行不能超过120个字符。
●规则4.5.2:
长表达式要在低优先级操作符处拆分成新行,操作符放在新行之首(以便突出操作符)。
拆分出的新行要进行4格缩进,使排版整齐,语句可读。
4.6修饰符的位置
●规则4.6.1:
必须将修饰符*和&紧靠变量名。
4.7注释
C语言的注释符为”/*…*/”。
注释通常用于:
(1)版本、版权声明;
(2)函数接口说明;
(3)重要的代码行或段落提示。
●规则4.7.1:
注释符为”/*……*/”,“/*”之后和“*/”之前留一个空格。
注释率要达到代码量的40%,同时注意注释的有效性。
注释量的计算按如下方法:
注:
如果一行中既有代码又有注释,则既算一行代码,也算一行注释。
●规则4.7.2:
注释的位置应与被描述的代码相邻,可以放在代码的上方或右方,不可放在下方。
如果注释内容有多行,则必须放在代码上方,而且与被注释代码缩进相同。
●规则4.7.3:
必须在每个函数定义前加一个指定格式的函数说明(函数头),描述该函数的功能、参数、返回值、说明等。
函数头的模版具体见附件章节中的“函数头模板”
●规则4.7.4:
边写代码边注释,修改代码同时修改相应的注释,以保证注释与代码的一致性。
不再有用的注释要删除。
●规则4.7.5:
注释使用英文进行描述。
●建议4.7.1:
当代码比较长,特别是有多重嵌套时,应当在一些段落的结束处加注释,便于阅读。
●建议4.7.2:
尽量避免在注释中使用缩写,特别是不常用缩写。
5语言编写
5.1表达式
●规则5.1.1:
在表达式中用括号使子表达式的运算顺序清晰;必须确保表达式中的操作数的运算顺序不会对表达式的值造成影响,尤其在可能有副作用的子表达式中,必须保证有准确定义的运算顺序。
●规则5.1.2:
在一条语句中只能对某一变量/对象的值做一次修改。
反例:
一条语句中对同一变量的多次修改
y=(x++)*(x++);
●规则5.1.3:
不要在同一条I/O输入语句中用刚赋值的变量再做参数调用。
●建议5.1.1:
不要在逻辑表达式中使用按位操作符”&”和”|”。
●建议5.1.2:
表达式尽可能清晰简明;避免表达式中的副作用。
●建议5.1.3:
在if,for和while语句中要使用布尔型控制表达式。
如果该表达式不是逻辑表达式,就用显式验证。
反例:
表达式隐式验证
while(a+b)
范例:
表达式显式验证
while((a+b)!
=0)
●建议5.1.4:
在写if语句的条件时,如果是变量和常量的比较关系,最好将常量放在前面。
●建议5.1.5:
尽量避免表达式中混有带符号数和无符号数。
当带符号数和无符号数混和运算时,有符号数有可能转变为无符号数。
如果有符号数是个负数,转换后可能变为正数。
这可能导致不可预料的结果。
●建议5.1.6:
避免逻辑表达式的结果为恒真或恒假。
这样的判断往往是毫无意义的,有时也是潜在隐藏的bug,不能到达程序的某些部分。
5.2声明和定义
●规则5.2.1:
全局常量、变量或函数的定义和所有声明要始终使用一致的类型,切不可在局部来声明和定义它们。
在一个所有使用该类型的源程序都包含的头文件中声明全局常量、变量或函数,可以避免这个问题。
●规则5.2.2:
在整个子系统中唯一地定义源文件级局部类型。
●规则5.2.3:
要使用在项目级定义的类型别名,不要用固有数据类型(enum例外),这样代码不依赖于特定的编译环境,可移植性较好。
●规则5.2.4:
永远将extern,static和register写在具有这些属性的声明或定义的行首。
●规则5.2.5:
要明确地指明函数返回值的类型。
●建议5.2.1:
函数内部使用的变量,其声明和定义放在函数的开始处。
●建议5.2.2:
在变量的可见空间内不要定义重名变量。
●建议5.2.3:
在最小可能的范围内声明变量。
●建议5.2.4:
局部变量占用内存不能太大(<1K),以避免栈越界。
●建议5.2.5:
大的全局变量或静态变量(>16K)不要在声明的时候初始化,而是程序运行后进行初始化。
这样可以减少版本大小,加快版本编译速度。
5.3整数数据类型及操作
C语言中提供了三种“整型”:
字符型:
char,又可加上修饰符signed,unsigned;
int型:
包括short,long两种,又可加上修饰符signed,unsigned;
枚举型:
enum。
C中没有严格的类型检查,比如它允许在表达式和变量中混用整型,此时编译器自动完成转换(隐式转换),结果依赖于特定的工具,这样的数据操作通常是危险的。
●规则5.3.1:
只能对无符号整数进行移位操作;(除DSP相关算法外,在预知结果的情况下,可以对有符号数进行移位操作)。
ANSIC没有对负数右移位的结果作规定。
而负数左移位会改变其符号和值,且改变的结果不可预知。
●规则5.3.2:
移动的位数只能大于等于0并小于等于被移变量的长度。
●建议5.3.1:
在除”/”取模操作中,用显式检查避免被0除或模0。
如果操作数符号不同,使用标准库函数div和ldiv代替除/取模操作。
●建议5.3.2:
在程序的关键部分加充分的检查,以防止并保护上溢和下溢。
●建议5.3.3:
不要用数字直接表示结构的偏移量,要用宏offsetof。
●建议5.3.4:
对于不应有负值的变量用无符号整型(unsigned)定义。
●建议5.3.5:
只能将enum型变量与同类型变量相比较。
虽然不同enum类型的变量相比较不会出现语法错误,但是会影响程序的可读性和逻辑性。
5.4字符操作
●建议5.4.1:
不要对字符集的顺序做任何假设。
●建议5.4.2:
显式定义带符号或无符号字符。
●建议5.4.3:
如果用8位ASCII码,将char设置为无符号。
5.5浮点型
C提供浮点类型float,double和longdouble,其表示法在标准头文件
●规则5.5.1:
要恰当地进行两个浮点数之间的比较,不要直接使用”==”或”!
=”比较。
5.6类型转换
类型转换分为隐式类型转换和显式类型转换。
●规则5.6.1:
对于不同类型,必须强制转换。
●规则5.6.2:
不能对const定义的常量进行类型转换(对某些处理器从优化效率方面考虑有特殊要求的除外)。
●建议5.6.1:
尽量不做指针和非指针类型之间的转换。
●建议5.6.2:
切不可将指向函数的指针转换为指向对象或其他任何类型的指针,反之亦不可。
●建议5.6.3:
强制类型转换以后,要用”&”操作对结果进行保护。
5.7常量
●规则5.7.1:
代码中不要直接使用具有某种意义的数字,而要用符号值代替。
不希望被改变的数字必须定义为常量或宏,这一规则也适用于字符串。
●建议5.7.1:
利用语句sizeof去计算对象的大小而不要使用常数。
5.8指针
●规则5.8.1:
不要对指针进行”!
”,”&&”,或”||”操作,不要将两个指针相加;只能对指向相同数组的指针进行比较或相减。
两个指针相减,仅在两个指针指向同一数组中的元素时有效。
指针和整型数n相加,结果为一个指针,该指针与原指针之间相距n个元素。
●建议5.8.1:
避免用指针指向指针。
5.9数组
●规则5.9.1:
不要将数组声明为函数的参数,用指针符号。
●建议5.9.1:
对多维数组的操作尽量用下标符号。
5.10函数与宏
●规则5.10.1:
在有非空结果的函数的所有结束处写返回语句。
●规则5.10.2:
如果在宏定义中使用了表达式,则一定要用括号把宏定义中表达式括起来。
●规则5.10.3:
在函数原型声明中确定参数的名字,在函数定义中使用相同的名字。
●规则5.10.4:
空函数必须打印提示信息,说明目前执行的是空操作。
●规则5.10.5:
函数大小不超过300有效代码行,最好不超过150有效代码行。
●建议5.10.6:
避免函数带过多参数,超过7个参数即认为过多。
●建议5.10.7:
不要在用户自定义的函数中使用变参数列表。
●建议5.10.8:
用宏定义表达式时,要使用完备的括号。
反例:
#defineRECTANGLE_AREA(a,b)a*b
#defineRECTANGLE_AREA(a,b)(a*b)
#defineRECTANGLE_AREA(a,b)(a)*(b)
正例:
#defineRECTANGLE_AREA(a,b)((a)*(b))
●建议5.10.9:
将宏所定义的多条表达式放在大括号中。
反例:
#defineINTI_RECT_VALUE(a,b)\
a=0;\
b=0;
for(index=0;index INTI_RECT_VALUE(rect.a,rect.b); 正例: #defineINTI_RECT_VALUE(a,b)\ {\ a=0;\ b=0;\ } for(index=0;index { INTI_RECT_VALUE(rect[index].a,rect[index].b); } 5.11控制语句 ●建议5.11.1: 禁止使用goto语句,特别是局部的goto语句。 ●建议5.11.2: 使用switch语句的建议: -条件不是彼此互斥时,不要用switch语句; -为switch表达式和case标签选择匹配的类型; -在switch语句中,所有的case标签要采用同一个enum类型;即: 如果case标签是enum类型的话,不能用不同的enum类型。 -在switch语句的末尾写一条非空的default语句; -不能在switch和第一个case之间放置语句; -在每个case语句后,书写相应的注释; -每个case标签要以break语句结束; -对于switch语句下的case语句,如果因为特殊情况需要处理完一个case后进入下一个case处理,必须在该case语句处理完、下一个case语句前加上明确的注释; -case语句要求缩进。 -当switch/case构成的代码块超过30行时,表示结束的“}”后需要注释/*endofswitch(…)*/ -switch/case代码块中的语句必须使用“{”和“}”包裹,“{”和“}”各自独占1行 ●建议5.11.3: if/elseif/else语句的写法: else-if语句应该写成条件从上向下读,遇到第一个能够满足的条件,就执行所对应的语句部分,而随后的结构都跳过去,最后一个else处理默认情况(即没有选中其他部分时的情况)或者给出一个错误信息。 当if/elseif/else构成的代码块超过30行时,表示结束的“}”后需要注释/*endofif(…)*/或/*endofelseif(…)*/或/*endofelse(…)*/ if/elseif/else代码块中的语句必须使用“{”和“}”包裹,“{”和“}”各自独占1行 ●建议5.11.4: for循环语句的写法: 循环语句尽量用for语句编写,并尽可能使用for(iLoop=0;iLoop<=iMaxValue;iLoop++)的格式,保证循环变量的增量操作写在for语句括号中第二个分号后。 当for循环构成的代码块超过30行时,表示结束的“}”后需要注释/*endoffor(…)*/ for循环块中的语句必须使用“{”和“}”包裹,“{”和“}”各自独占1行 不允许使用BYTE类型作为循环控制变量,以免出现意外的死循环。 ●建议5.11.5: while/dowhile循环语句的写法: 循环语句尽量用for语句编写,并尽可能使用for(iLoop=0;iLoop<=iMaxValue;iLoop++)的格式,保证循环变量的增量操作写在for语句括号中第二个分号后。 当while循环构成的代码块超过30行时,表示结束的“}”后需要注释/*endofwhile(…)*/ while循环块中的语句必须使用“{”和“}”包裹,“{”和“}”各自独占1行 dowhile循环块中的语句必须使用“{”和“}”包裹,“{”独占1行,”}”和while合占1行 不允许使用INT8类型作为循环控制变量,以免出现意外的死循环。 ●规则5.11.6: 不允许使用逗号操作符。 ●规则5.11.7: 不允许使用条件运算符。 ●规则5.11.8: 不允许使用三元操作符,以条件语句取代。 5.12内存分配 ●规则5.12.1: 使用完所分配的内存后必须立即释放。 ●建议5.12.1: 不要用同一个指针既指向数组又指向单个的对象。 ●建议5.12.2: 当指针指向被释放的内存时,应给该指针赋NULL。 ●建议5.12.3: 对于小于1k的局部对象,在堆栈(stack)而不是在堆(heap)中分配局部对象。 ●建议5.12.3: 对于局部对象,要求大小小于1k,否则应该考虑使用其它方式。 5.13错误处理 ●规则5.13.1: 如果被调用的函数有返回值,要针对不同的返回值进行相应的判断并作相应的处理;如果返回值可能正确也可能错误,一定要对其进行差错检查。 5.14断言 断言函数可以用来明确地表达先决条件和后置条件,也可以用来记录和调试。 断言使用逻辑表达式(布尔型)作为参数,能够在程序中的任意位置调用。 如果表达
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 语言 编程 规范
![提示](https://static.bdocx.com/images/bang_tan.gif)