如何编写高质量程序--学习总结篇

0 各种鸟的pk

新手,又名菜鸟,能尝试写出一些满足要求的程序。
编程老手,老鸟,能长期稳定地编写出高质量程序的程序员。
编程高手,大佬,能长期稳定地编写出高难度、高质量程序的程序员。

备注:CMMI是软件能力成熟度集成模型,分为5级。

进来阅读林锐博士的《高质量C编程指南》,从代码规范上获益良多,特总结一下。

1 项目规划

采用项目管理的相关要求,明确项目的时间节点、项目的主要目标和非目标,目标细分成各种小任务,项目团队零时搭建和分工,项目的资源等分析,时间进度规划等等。

2 文件结构

C和C++一般由头文件(以.h为后缀)、程序文件(以.c,.cpp,.cc,.cxx为后缀)。

如果一个软件的头文件数目比较多(如超过十个),通常应将头文件和定义文件分别保存于不同的目录,以便于维护。可将头文件保存于include目录,将定义文件保存于source目录(可以是多级目录)。

2.1 头文件

头文件是用于保持程序的声明。通过头文件来调用库功能和加强类型安全检查。

包括版权信息,文件名称摘要,当前版本信息,历史版本信息,预处理块,函数和类结构等声明。

其中:
为了防止头文件被重复引用,应当用ifndef/define/endif结构产生预处理块。
用 #include <filename.h> 格式来引用标准库的头文件(编译器将从标准库目录开始搜索)。
用 #include “filename.h” 格式来引用非标准库的头文件(编译器将从用户的工作目录开始搜索)。
头文件中只存放“声明”而不存放“定义”。
在头文件中最好不用全局变量,不要出现extern int value这类声明。

/* 
* Copyright (c) 2019,XX有限公司XX部门
* All rights reserved. 
*
* 文件名称:filename.h
*  文件标识:见配置管理计划书
*  摘 要:简要描述本文件的内容
* 
*  当前版本:V1.1 
*  作 者:输入作者(或修改者)名字 ,邮箱
*  完成日期:2019年05月19日 
* 
*  取代版本:V1.0 
*  原作者 :输入原作者(或修改者)名字,邮箱
* 完成日期:2019年5月10日
*/

#ifndef	GRAPHICS_H	// 防止graphics.h被重复引用
#define	GRAPHICS_H

#include <math.h>	// 引用标准库的头文件
…
#include “myheader.h” // 引用非标准库的头文件
…
void Function1(…);	// 全局函数声明
…
class Box	// 类结构声明
{
…
};
#endif

2.2 源文件

定义文件为,开头处的版权和版本声明,对一些头文件的引用,程序的实现体(包括数据和代码)。

/* 
* Copyright (c) 2019,XX有限公司XX部门
* All rights reserved. 
*
* 文件名称:filename.C
*  文件标识:见配置管理计划书
*  摘 要:简要描述本文件的内容
* 
*  当前版本:V1.1 
*  作 者:输入作者(或修改者)名字 ,邮箱
*  完成日期:2019年05月19日 
* 
*  取代版本:V1.0 
*  原作者 :输入原作者(或修改者)名字,邮箱
* 完成日期:2019年5月10日
*/

#include “graphics.h”	// 引用头文件
…
// 全局函数的实现体
void Function1(…)
{
…
}
// 类成员函数的实现体
void Box::Draw(…)
{
…
}

3 具体程序

不要吝啬空行和空格,他们不会增加代码的存储大小。

一行代码只做一件事情,定义变量或者是一条语句,在定义变量的同时最好将其初始化。

if、for、while、do等语句占一行,不论执行语句多长,都记得加‘{’、‘}’。

3.1 空行

程序好的布局需要空行,在每个类声明之后、每个函数定义结束之后都要加空行;在一个函数体内,逻辑上密切相关的语句之间不加空行,其它地方应加空行分隔。

3.2 空格

关键字之后要留空格。象const、virtual、inline、case 等关键字之后至少要留一个空格,否则无法辨析关键字。象if、for、while等关键字之后应留一个空格再跟左括号‘(’,以突出关键字。

函数名之后不要留空格,紧跟左括号‘(’,以与关键字区别。void Func1(int x, int y, int z);

向前紧跟的“,”、“(”、“)”、“;”都不留空格;‘,’之后要留空格,如Function(x, y, z);’;’不是一行的结束符号,其后要留空格,如for (initialization; condition; update)。

赋值操作符、比较操作符、算术操作符、逻辑操作符、位域操作符,如“=”、“+=” “>=”、“<=”、“+”、“*”、“%”、“&&”、“||”、“<<”,“^”等二元操作符的前后应当加空格。

一元操作符如“!”、“~”、“++”、“–”、“&”(地址运算符)等前后不加空格。

象“[]”、“.”、“->”这类操作符前后不加空格。

对较长if或for表达式可适当去掉一些空格。

3.3 对齐

程序的分界符‘{’和‘}’应独占一行并且位于同一列,同时与引用它们的语句左对齐。

{ }之内的代码块在‘{’右边数格处左对齐。

利用“Tab”进行对齐,注意不要随便更改软件Tab的大小,一般设定为4个空格。

3.4 拆分

代码行最大长度宜控制在70至80个字符以内。代码行不要过长,否则眼睛看不过来,也不便于打印。

长表达式要在低优先级操作符处拆分成新行,操作符放在新行之首(以便突出操作符)。拆分出的新行要进行适当的缩进,使排版整齐,语句可读。

if ((very_longer_variable1 >= very_longer_variable12)
	&& (very_longer_variable3 <= very_longer_variable14)
	&& (very_longer_variable5 <= very_longer_variable16))
{
		dosomething();
}

3.5 修饰符

将修饰符 * 和 & 紧靠变量名。

char *name;

int *x, y;	// 此处y不会被误解为指针,最好拆分为int *x; int y;

3.6 注释

C语言的注释符为“//”。C++语言中,程序块的注释常采用“//”,行注释一般采用“//…”。

注释通常用于:
(1)版本、版权声明;
(2)函数接口说明;
(3)重要的代码行或段落提示。

注释是对代码的“提示”,便于理解,要少而精,不可过多和过于花哨。
简单明了地方不需要注释。

边写代码边注释,不应该产生歧义和使用缩写,修改代码同时修改相应的注释,以保证注释与代码的一致性。不再有用的注释要删除。

代码较长时,或者有多重嵌套时,应当在段落的结束处加注释,便于阅读。

3.7 类

类可以将数据和函数封装在一起,其中函数表示了类的行为(或称服务)。

类提供关键字 public、protected 和 private,分别用于声明哪些数据和函数是公有的、受保护的或者是私有的。

将 public 类型的函数写在前面,而将 private 类型的数据写在后面,以行为为中心,重点关注
的是类应该提供什么样的接口(或服务)。

class A
{
	public:
	void Func1(void);
	void Func2(void);
	…
	private:
	int i, j;
	float x, y;
	…
}

4 命名

常用的命名规范有“匈牙利”法,驼峰法,帕斯卡命名法。

常用命名方法推荐为:

  1. 标识符应当直观且可以拼读,可望文知意,不必进行“解码”。

  2. Windows 应用程序的标识符通常采用“大小写”混排的方式,如AddChild。 而 Unix 应用程序的标识符通常采用“小写加下划线”的方式,如add_child。别把这两类风格混在一起用。

  3. 程序中不要出现仅靠大小写区分的相似的标识符。例如fo和F0。

  4. 程序中不要出现标识符完全相同的局部变量和全局变量,尽管两者的作用域不同而不会发生语法错误,但会使人误解。

  5. 变量的名字应当使用“名词”或者“形容词+名词”。float Value; float oldValue;

  6. 全局函数的名字应当使用“动词”或者“动词+名词”(动宾词组)。类的成员函数应当只使用“动词”,被省略掉的名词就是对象本身。DrawBox(); // 全局函数 box->Draw(); // 类的成员函数

  7. 用正确的反义词组命名具有互斥意义的变量或相反动作的函数等。

Unix linux系统采用的命名方法为:

  1. 变量和函数都采用小写加下划线分割单词。

  2. 大写字母留给宏和枚举常量,以及根据统一惯例的常量。

  3. 函数名瞎用下划线分割小写字母的方式命名,例如设备名_操作名() ——
    dev0_open();而操作名一般采用谓语动词或者谓语+宾语/表语,例如tic_init();abc_is_busy();uart_tx_char(); 中断函数命名直接使用设备名_isr()。

  4. 变量命名长度应该合适,准确不产生歧义;单字符作为函数的内局部变量;tmp为零时变量名;局部静态变量s_;全局变量加g_。

  5. 不建议大小写混用,临时变量可以用较短命名。

  6. 某应用程序下的函数遵循——属于某一模块的函数,加上模块简写缩写做前缀;函数表明函数意义格式为“前缀_名词_动词”。

5 表达式

5.1 运算符优先级

优先级运算符运算符
1后缀运算符:[] () · -> ++ --(类型名称){列表}从左到右
2一元运算符:++ – ! ~ + - * & sizeof_Alignof从右到左
3类型转换运算符:(类型名称)从右到左
4乘除法运算符:* / %从左到右
5加减法运算符:+ -从左到右
6移位运算符:<< >>从左到右
7关系运算符:<<= >>=从左到右
8相等运算符:== !=从左到右
9位运算符 AND:&从左到右
10位运算符 XOR:^从左到右
11位运算符 OR:1从左到右
12逻辑运算符 AND:&&从左到右
13逻辑运算符 OR:11从左到右
14条件运算符:?:从右到左
15赋值运算符: = , += , -= , *=, /= , %= , &= , ^= , 1 =, <<= , >>=从右到左
16逗号运算符:,从左到右

注意:因编辑器原因,其中或等运算符|,采用1代替。

5.2 判断语句

1)不可将布尔变量直接与 TRUE、 FALSE 或者 1、 0 进行比较

根据布尔类型的语义,零值为“假”(记为 FALSE),任何非零值都是“真”(记为TRUE)。 TRUE 的值究竟是什么并没有统一的标准。

所以标准判断为:

if (flag) // 表示 flag 为真
if (!flag) // 表示 flag 为假

下面的用法属于不规范

if (flag == TRUE)
if (flag == 1 )
if (flag == FALSE)
if (flag == 0)

2)整型变量与零值比较

应当将整型变量用“ ==”或“! =”直接与 0 比较。不可模仿布尔变量的风格而写成

if (value) // 会让人误解 value 是布尔变量

浮点变量与零值比较
不可将浮点变量用“ ==”或“! =”与任何数字比较,应该设法转化成“ >=”或“ <=”形式。

// 假设浮点变量的名字为 x,应当将
    if (x == 0.0) // 隐含错误的比较
//  转化为
    if ((x>=-EPSINON) && (x<=EPSINON))
//  其中 EPSINON 是允许的误差(即精度)

指针变量与零值比较

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值