高质量编程规范.ppt

上传人:rrsccc 文档编号:8993069 上传时间:2021-01-28 格式:PPT 页数:61 大小:209.50KB
返回 下载 相关 举报
高质量编程规范.ppt_第1页
第1页 / 共61页
高质量编程规范.ppt_第2页
第2页 / 共61页
高质量编程规范.ppt_第3页
第3页 / 共61页
高质量编程规范.ppt_第4页
第4页 / 共61页
高质量编程规范.ppt_第5页
第5页 / 共61页
点击查看更多>>
资源描述

《高质量编程规范.ppt》由会员分享,可在线阅读,更多相关《高质量编程规范.ppt(61页珍藏版)》请在三一文库上搜索。

1、上章回顾,哈希函数的构造方法有那些 哈希表中处理冲突的方法有那些,高质量编程规范,第八章,预习检查,C语言要经历哪几个编译过程 如何申请链表单元,及释放链表单元 实现单链表插入的基本语法 简述一下快速排序基本理论要点,课程目标,本章概述 阐述如何进行高质量的编程,以及注意事项 本章目标 了解高质量编程注意的方方面面 从代码风格,算法,方便调试,性能等。 重点 内存分配与释放,悬挂指针,本章结构,程序员的态度,高质量编程规范,微观上高质量,宏观上高质量,8.1 程序员的态度,程序员的弱点 不太愿意测试自己的代码 不愿意REVIEW团队队员的代码 程序员重点 保证自己的代码没有 BUG 来,8.1

2、 程序员的态度,程序员自身可以在程序生成的流程 详细设计 编写代码 单元测试 功能测试 代码 REVIEW,8.1.1 编码的风格,版权和版本的申明 头文件的结构 定义文件的结构 头文件的作用 目录结构 命名规则 注释规则,/* Copyright (c) 2001,上海贝尔有限公司网络应用事业部 * All rights reserved.* * 文件名称:filename.h * 文件标识:见配置管理计划书 * 摘 要:简要描述本文件的内容* * 当前版本:1.1 * 作 者:输入作者(或修改者)名字 * 完成日期:2001年7月20日* * 取代版本:1.0 * 原作者 :输入原作者(或

3、修改者)名字 * 完成日期:2001年5月10日,8.1.1.1 版权和版本的申明,版权和版本的声明位于头文件和定义文件的开头,主要内容有: (1)版权信息。 (2)文件名称,标识符,摘要。 (3)当前版本号,作者/修改者,完成日期。 (4)版本历史信息。 范例,8.1.1.2头文件的结构,头文件由三部分内容组成: 头文件开头处的版权和版本声明。 预处理块。 函数和类结构声明等。 范例 为了防止头文件被重复引用,应当用ifndef/define/endif结构产生预处理块。 用 #include 格式来引用标准库的头文件(编译器将从标准库目录开始搜索)。 用 #include “filenam

4、e.h” 格式来引用非标准库的头文件(编译器将从用户的工作目录开始搜索)。 头文件中只存放“声明”而不存放“定义” 不提倡使用全局变量,尽量不要在头文件中出现象extern int value 这类声明。,8.1.1.3定义文件的结构,定义文件有三部分内容: 定义文件开头处的版权和版本声明 对一些头文件的引用 程序的实现体(包括数据和代码) 范例,/ 版权和版本声明 #include “graphics.h” / 引用头文件 / 全局函数的实现体 void Function1() ,8.1.1.4 头文件的作用,通过头文件来调用库功能 头文件能加强类型安全检查,8.1.1.5 目录结构,特点:

5、 便于维护 通常应将头文件和定义文件分别保存于不同的目录 加强信息隐藏 :如果某些头文件是私有的,它不会被用户的程序直接引用,则没有必要公开其“声明” 范例: Network 工程建立三个目录 source:存放工程源文件,如:server.c Client.c Include:存放工程头文件,如:server.h Client.h Lib:存放工程库文件,如:tipr.so stdio.so,8.1.1.6 命名规则,主要思想:在变量和函数名中加入前缀以增进人们对程序的理解 具体规则: 标识符应当直观且可以拼读,可望文知意,不必进行“解码”。 标识符的长度应当符合“min-length 向前

6、紧跟,紧跟处不留空格 ,之后要留空格 二元操作符的前后应当加空格。 一元操作符前后不加空格。 象“”、“.”、“-”这类操作符前后不加空格。,8.1.2.4 对齐和拆分规则,对齐规则 程序的分界符和应独占一行并且位于同一列,同时与引用它们的语句左对齐 之内的代码块在右边数格处左对齐。 长行拆分规则 代码行最大长度宜控制在70至80个字符以内 长表达式要在低优先级操作符处拆分成新行,操作符放在新行之首(以便突出操作符)。拆分出的新行要进行适当的缩进,使排版整齐,语句可读,8.1.2.5 长行拆分规则,代码行最大长度宜控制在70至80个字符以内 长表达式要在低优先级操作符处拆分成新行,操作符放在新

7、行之首(以便突出操作符) 例:,if (very_longer_variable1 = very_longer_variable12) ,8.1.2.6 修饰符的位置,修饰符 * 和 修饰符 紧靠变量名 例如: char *name; int *x, y;/ 此处y不会被误解为指针,x? y?,8.1.2.7 注释,C语言的注释符为“/*/” 行注释一般采用“/” 注释通常用于 版本、版权声明; 函数接口说明; 重要的代码行或段落提示。,8.1.2.7 注释,注释规则 注释是对代码的“提示”,而不是文档 如果代码本来就是清楚的,则不必加注释。 边写代码边注释 注释应当准确、易懂,防止注释有二义

8、性 尽量避免在注释中使用缩写,特别是不常用缩写。 注释的位置应与被描述的代码相邻 当代码比较长,应当在一些段落的结束处加注释,8.1.2.7 注释,注释实例,/* * 函数介绍: * 输入参数: * 输出参数: * 返回值 : */ void Function(float x, float y, float z) ,阶段小节,版权的申明和头文件的结构及作用 命名的规则 代码的版式规则 空行 对齐 拆分 代码的注释,8.2 微观上的高质量,程序的健壮性 防止内存泄漏 编程的优化,8.2.1程序的健壮性,使用断言 复合表达式 If语句 使用const提高函数的健壮性,8.2.1.1使用断言,程序一

9、般分为Debug版本和Release版本 断言assert是仅在Debug版本起作用的宏 断言优势: 跟踪程序运行,帮助调试 输出错误原因 可以自定义,8.2.1.1使用断言,使用断言规则: 使用断言捕捉不应该发生的非法情况 在函数的入口处,使用断言检查参数的有效性(合法性)。 一旦确定了的假定,就要使用断言对假定进行检查。 如果“不可能发生”的事情的确发生了,则要使用断言进行报警,8.2.1.2 复合表达式,复合表达式例子 a = b = c = 0 优势: 书写简洁 提高编译效率,8.2.1.2 复合表达式,复合表达式使用规则 不要编写太复杂的复合表达式。 例子:i = a = b 不要把

10、程序中的复合表达式与“真正的数学表达式”混淆 if (a b c) 与 if (ab) 如果输入参数采用“引用传递 ”, 可以避免修改参数值的值传递 void Func(const A 如下语句将出现编译错误: char *str = GetString(); 正确的用法是 const char *str = GetString();,8.3.1 防止内存泄漏,内存分配方式 malloc/free 的使用要点 常见的内存错误及其对策 引用与指针的比较 指针与数组的对比 指针参数是如何传递内存的 动态内存自动释放 杜绝“野指针”,8.3.1.1内存分配方式,内存分配方式有三种: 从静态存储区域分

11、配 在栈上创建 从堆上分配,亦称动态内存分配 malloc或new free或delete,8.3.1.2 malloc/free 的使用要点,malloc 语法:void * malloc(size_t size); 作用:申请一块长度为length的整数类型的内存 例子:int *p = (int *) malloc(sizeof(int) * length) Free 语法:void free( void * memblock ) 作用:释放内存 例子:free(p) 如果p是NULL指针,那么free对p无论操作多少次都不会出问题 如果p不是NULL指针,那么free对p连续操作两次就

12、会导致程序运行错误。,8.3.1.3 常见的内存错误及其对策,常见的内存错误 内存分配未成功,却使用了它 内存分配虽然成功,但是尚未初始化就引用它 内存分配成功并且已经初始化,但操作越过了内存的边界 忘记了释放内存,造成内存泄露 释放了内存却继续使用它,8.3.1.3 常见的内存错误及其对策,内存管理的规则 用malloc之后,应该立即检查指针值是否为NULL。防止使用指针值为NULL的内存。 不要忘记为数组和动态内存赋初值。防止将未被初始化的内存作为右值使用。 避免数组或指针的下标越界,特别要当心发生“多1”或者“少1”操作。 动态内存的申请与释放必须配对,防止内存泄漏。 用free释放了内

13、存之后,立即将指针设置为NULL,防止产生“野指针”。,8.3.1.5 指针与数组的对比,差别 数组: 要么在静态存储区被创建(如全局数组),要么在栈上被创建 数组名对应着(而不是指向)一块内存 其地址与容量在生命期内保持不变 只有数组的内容可以改变 指针: 随时指向任意类型的内存块 动态生存 在数据堆,8.3.1.5 指针与数组的对比,差别 内存的容量大小 例:1 例2,char a = hello world; char *p = a; sizeof(a) ?/ 12字节 sizeof(p) ?/ 4字节,void Func(char a100) sizeof(a) ? / 4字节而不是1

14、00字节 ,8.3.1.5 指针与数组的对比,动态内存会自动释放 不会自动释放 例: 指针应该注意的特性 指针消亡了,并不表示它所指的内存会被自动释放。 内存被释放了,并不表示指针会消亡或者成了NULL指针。,void Func(void) char *p = (char *) malloc(100); / 动态内存会自动释放吗? ,8.3.1.6 指针参数是如何传递内存的,*如果函数的参数是一个指针,不要指望用该指针去申请动态内存,void GetMemory(char *p, int num) p = (char *)malloc(sizeof(char) * num); void Tes

15、t(void) char *str = NULL; GetMemory(str, 100); / str 仍然为 NULL strcpy(str, hello);/ 运行错误 ,8.3.1.6 指针参数是如何传递内存的,*如果函数的参数是一个指针,不要指望用该指针去申请动态内存,void GetMemory2(char *p, int num) *p = (char *)malloc(sizeof(char) * num); void Test(void) char *str = NULL; GetMemory(/ 运行错误 ,8.3.1.6 指针参数是如何传递内存的,* 不要用return语

16、句返回指向“栈内存”的指针,char *GetString(void) char p = hello world; return p; / 编译器将提出警告 void Test4(void) char *str = NULL; str = GetString(); / str 的内容是垃圾 printf(“%sn”,str ); ,8.3.1.7动态内存自动释放,free函数特点 释放指针所指的内存 没有销毁指针,故指针地址仍然不变(非NULL) 例:,char *p = (char *) malloc(100); strcpy(p, “hello”); free(p); / p 所指的内存被

17、释放,但是p所指的地址仍然不变 if(p != NULL) strcpy(p, “world”);/ 出错 ,没有起到防错作用,8.3.1.8 杜绝“野指针”,什么是“野指针” 不是NULL指针 是指向“垃圾”内存的指针 If(p!=NULL)不能起到作用 野指针的成因 指针变量没有被初始化 指针初始化: char *p = NULL; char *str = (char *) malloc(100); 指针p被free或者delete之后,没有置为NULL,8.3.2 编程的优化,为什么需要常量 Const与#define的比较 常量定义规则 循环语句的效率 For语句的循环控制变量,8.3

18、.2.1 为什么用常量,常量是一种标识符,它的值在运行期间恒定不变。 用 #define来定义常量(称为宏常量),还可以用const来定义常量 为什么要常量 程序的可读性 在程序的很多地方输入同样的数字或字符串,难保不发生书写错误。 如果要修改数字或字符串,则会在很多地方改动,既麻烦又容易出错。 尽量使用含义直观的常量来表示那些将在程序中多次出现的数字或字符串。 例如: #define MAX 100/* C语言的宏常量 */ const int MAX = 100;/ C 语言的const常量 const float PI = 3.14159;/ C 语言的const常量,8.3.2.2 c

19、onst 与 #define的比较,两种区别比较 const常量有数据类型,而宏常量没有数据类型。 编译器可以对前者进行类型安全检查。而对后者只进行字符替换,没有类型安全检查 有些集成化的调试工具可以对const常量进行调试,但是不能对宏常量进行调试。 常量定义规则 需要对外公开的常量放在头文件中,不需要对外公开的常量放在定义文件的头部 为便于管理,可以把不同模块的常量集中存放在一个公共的头文件中。 如果某一常量与其它常量密切相关,应在定义中包含这种关系,而不应给出一些孤立的值。 例如: const float RADIUS = 100; const float DIAMETER = RADI

20、US * 2;,8.3.2.3循环语句的效率,在多重循环中,如果有可能,应当将最长的循环放在最内层,最短的循环放在最外层,以减少CPU跨切循环层的次数。 如果循环体内存在逻辑判断,并且循环次数很大,宜将逻辑判断移到循环体的外面。,for (row=0; row100; row+) for ( col=0; col5; col+ ) sum = sum + arowcol; ,if (condition) for (i=0; iN; i+) DoSomething(); else for (i=0; iN; i+) DoOtherthing(); ,8.3.2.4 for语句的循环控制变量,循环

21、控制变量规则 不可在for 循环体内修改循环变量,防止for 循环失去控制 建议for语句的循环控制变量的取值采用“半开半闭区间”写法 例子:,半开半闭区间,闭区间,for (x=0; xN; x+) ,for (x=0; x=N; x+) ;,8.3.2.5 Pragma预处理,其格式一般为: #Pragma Para 其中Para 为参数,下面来看一些常用的参数。 #pragma message 编译信息输出窗口中输出相应的信息,这对于源代码信息的控制是非常重要的。其使用方法为: #Pragma message(“消息文本”) #pragma once 只要在头文件的最开始加入这条指令就能

22、够保证头文件被编译一次,这条指令实际上在VC6中就已经有了,但是考虑到兼容性并没有太多的使用它。 pragma comment(.) 该指令将一个注释记录放入一个对象文件或可执行文件中。 常用的lib关键字,可以帮我们连入一个库文件。,8.3.2.5 Pragma预处理,#pragma pack() 对于想结构体Struct这样的类型,VC采用8字节对齐的方式,如果我们不想使用8字节对齐(在网络变成中经常需要这样),我们可以在结构体前面加上 #pragma pack(1) struct . #pragma pack() #pragma warning #pragma warning( disa

23、ble : 4507 34; once : 4385; error : 164 ) 等价于: #pragma warning(disable:4507 34) / 不显示4507和34号警告信息 #pragma warning(once:4385) / 4385号警告信息仅报告一次 #pragma warning(error:164) / 把164号警告信息作为一个错误。,阶段小节,数值与0或者NULL的比较操作 内存分配注意细节 野指针 如何避免内存泄露 Const与define数据的差别 为什么要const数据,本章总结,程序员的态度,高质量编程规范,微观上高质量,宏观上高质量,主要讲述程序员在编程中的态度,讲述了程序编码风格和版式中具体细节,深入讲述C语言中内存管理和程序的健壮性和对程序编码的优化。,实验1,实验内容 编写strcpy函数-已知strcpy函数的原型是char *strcpy(char *strDest, const char *strSrc);其中strDest是目的字符串,strSrc是源字符串。 实验目的 编码的规范以及代码注释; const指针和内存的操作; assert函数错误检测利用; 内存的释放和数据的返回值; 实验分析 函数注释说明; 参数定义和内存申请和释放; assert数据检测和野指针检测实现; 数据返回值;,

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 社会民生


经营许可证编号:宁ICP备18001539号-1