您好,欢迎访问三七文档
当前位置:首页 > 电子/通信 > 综合/其它 > 优质C程序秘诀---附录
附录A编码检查表本附录给出的问题列表,总结了本书的所有观点。使用本表的最好办法是花两周时间评审一下你的设计和编码实现。先花几分钟时间看一看列表,一旦熟悉了这些问题,就可以灵活自如地按它写代码了。此时,就可以把表放在一边了。一般问题──你是否为程序建立了DEBUG版本?──你是否将发现的错误及时改正了?─一你是否坚持彻底测试代码.即使耽误了进度也在所不惜?──你是否依靠测试组为你测试代码?─一你是否知道编码的优先顺序?─一你的编译程序是否有可选的各种警告?关于将更改归并到主程序─一你是否将编译程序的警告(包括可选的)都处理了?──你的代码是否未用Lint─一你的代码进行了单元测试吗?─一你是否逐步通过了每一条编码路径以观察数据流?─一你是否逐步通过了汇编语言层次上的所有关键代码?──是否清理过了任何代码?如果是,修改处经过彻底测试了吗?─一文档是否指出了使用你的代码有危险之处?──程序维护人员是否能够理解你的代码?每当实现了一个函数或子系统之时─一是否用断言证实了函数参数的有效性?─一代码中是否有未定义的或者无意义的代码?─一代码能否创建未定义的数据?─一有没有难以理解的断言?对它们作解释了没有?─一你在代码中是否作过任何假设?─一是否使用断言警告可能出现的非常情况?─一是否作过防御性程序设计?代码是否隐藏了错误?─一是否用第二个算法来验证第一个算法?─一是否有可用于确认代码或数据的启动(startup)检查?─一代码是否包含了随机行为?能消除这些行为吗?──你的代码若产生了无用信息,你是否在DEBUG代码中也把它们置为无用信息?──代码中是否有稀奇古怪的行为?──若代码是子系统的一部分,那么你是否建立了一个子系统测试?──在你的设计和代码中是否有任意情况?──即使程序员不感到需要,你也作完整性检查吗?──你是否因为排错程序太大或太慢,而将有价值的DEBUG测试抛置一边?──是否使用了不可移植的数据类型?─一代码中是否有变量或表达式产生上溢或下溢?──是否准确地实现了你的设计?还是非常近似地实现了你的设计?──代码是否不止一次地解同一个问题?──是否企图消除代码中的每一个if语句?──是否用过嵌套?:运算符?──是否已将专用代码孤立出来?──是否用到了有风险的语言惯用语?─一是否不必要地将不同类型的运算符混用?──是否调用了返回错误的函数?你能消除这种调用吗?─一是否引用了尚未分配的存储空间?─一是否引用已经释放了的存储空间?──是否不必要地多用了输出缓冲存储?──是否向静态或全局缓冲区传送了数据?──你的函数是否依赖于另一个函数的内部细节?──是否使用了怪异的或有疑问的C惯用语?──在代码中是否有挤在一行的毛病?──代码有不必要的灵活性吗?你能消除它们吗?─一你的代码是经过多次“试着”求解的结果吗?─一函数是否小并容易测试?每当设计了一个函数或子系统后─一此特征是否符合产品的市场策略?─一错误代码是否作为正常返回值的特殊情况而隐藏起来?─一是否评审了你的界面,它能保证难于出现误操作吗?─一是否具有多用途且面面俱到的函数?─一你是否有太灵活的(空空洞洞的)函数参数?─一当你的函数不再需要时,它是否返回一个错误条件?─一在调用点你的函数是出易读?─一你的函数是否有布尔量输入?修改错误之时──错误无法消失,是否能找到错误的根源?─一是修改了错误的真正根源,还是仅仅修改了错误的症状?附录B内存登录例程本附录中的代码实现了第3章中讨论的内存登录例程的一个简单链表版本。这个代码有意作了简化使之便于理解,但这并不意味着它不可以用在那些大量地使用内存管理程序的应用之中。但在你花时间重写代码使其使用AVL树、B树或其它可以提供快速查找的数据结构之前,试一下这个代码验证它对于实际应用是否太慢了。你也许会发现这个代码很合用,特别是在没有分配许多全局共享的存储模块之时,更是如此。该文件中给出的实现是很直观的:每当分配一个内存块时,该例程就额外地分配一小块内存以存放blockinfo(块信息)结构,块信息中有登录信息(定义见下文)。当一个新的blockinfo结构创建时,就填充登录信息并置于链表结构的头部。该链表没有特意的顺序。再次说明,该实现是精选的,因为它既简单又容易理解。block.h:#ifdefDEBUG/*------------------------------------------------------------------------*blockinfo是个数据结构.它记录一个已分配内存块的存储登录信息。*每个已分配的内存块在内存登录中都有一个相应的blockinfo结构*/typedefstructBLOCKINFO{structBLOCKINFO*pbiNext;byte*pb;/*存储块的开始位置*/size_tsize;/*存储块的长度*/flagfReferenced;/*曾经引用过吗?*/}blockinfo;/*命名:bi、*pbi*/flagfCreateBlockInfo(byte*pbNew,size_tsizeNew);voidFreeBlockInfo(byte*pbToFree);voidUpdateBlockInfobyte(byte*pbOld,byte*pbNew,size_tsizeNew);size_tsizeofBlock(byte*pb);voidClearMemoryRefs(void);voidNoteMemoryRef(void*pv);voidCheckMemoryRefs(void);flagfValidPointer(void*pv,size_tsize);#endifblock.c:#ifdefDEBUG/*---------------------------------------------------------------------*该文件中的函数必须要对指针进行比较,而ANSI标准不能确保该操作是*可移植的。**下面的宏将该文件所需的指针比较独立出来。该实现采用了总能进行直接*比较的“直截了当”的指针,下面的定义对某些通用80x86内存模型不适用。*/#definefPtrLess(pLeft,pRight)((pLeft)(pRight))#definefPtrGrtr(pLeft,pRight)((pLeft)(pRight))#definefPtrEqual(pLeft,pRight)((pLeft)==(pRight))#definefPtrLEssEq(pLeft,pRight)((pLEft)=(pRight))#definefPtrGrtrEq(pLeft,pRight)((pLeft)=(pRright))/*------------------------------------------------------------------*//*****私有数据/函数*****//*------------------------------------------------------------------*//*------------------------------------------------------------------*pbiHead指向内存管理程序调试的单向链接列表。*/staticblockinfo*pbiHead=NULL;/*--------------------------------------------------------------------*pbiGetBlockInfo(pb)**pbiGetBlockInfo查询内存登录找到pb所指的存储块,并返回指向内*存登录中相应blockinfo结构的指针。注意:pb必须指向一个已分配的*存储块,否则将得到一个断言失败;该函数或者引发断言或者成功,它从*不返回错误。**blockinfo*pbi;*……*pbi=pbiGetBlockInfo(pb);*//pbi-pb指向pb所指存储块的开始位置*//pbi-size是pb所指存储块的大小*/staticblockinfo*pbiGetBlockInfo(byte*pb){blockinfo*pbi;for(pbi=pbiHead;pbi!=NULL;pbi=pbi-pbiNext){byte*pbStart=pbi-pb;/*为了可读性*/byte*pbEnd=pbi-pb+pbi-size–1;if(fPtrGrtrEq(pb,pbStart)&&fPtrLessEq(pb,pbEnd))break;}/*没能找到指针?它是(a)垃圾?(b)指向一个已经释放了的存储块?*或(c)指向一个在由fResizeMemory重置大小时而移动了的存储块?*/ASSERT(pbi!=NULL);return(pbi);}/*------------------------------------------------------------------*//*****公共函数*****//*------------------------------------------------------------------*//*------------------------------------------------------------------*/*fCreateBlockInfo(pbNew,sizeNew)**该函数为由pbNew:sizeNew定义的存储块建立一个登录项。如果成功地*建立了登录信息则该函数返回TRUE,否则返回FALSE。**if(fCreateBlockInfo(pbNew,sizeNew))*成功───该内存登录具有pbNew:sizeNew项*else*失败───由于没有该项则应释放pbNew*/flagfCreateBlockInfo(byte*pbNew,size_tsizeNew){blockinfo*pbi;ASSERT(pbNew!=NULL&&sizeNew!=0);pbi=(blockinfo*)malloc(sizeof(blockinfo));if(pbi!=NULL){pbi-pb=pbNew;pbi-size=sizeNew;pbi-pbiNext=pbiHead;pbiHead=pbi;}return(flag)(pbi!=NULL);}/*------------------------------------------------------------------*FreeBlockInfo(pbToFree)**该函数清除由pbToFree所指存储块的登录项。pbToFree必须指向一*个已分配存储块的开始位置,否则将得到一个断言失败。*/voidFreeBlockInfo(byte*pbToFree){blocinfo*pbi,*pbiPrev;for(pbi=pbiHead;pbi!=NULL;pbi=pbi-pbiNext){if(fPtrEqual(pbi-pb,pbToFree)){if(pbiPrev==NULL)pbiHead=pbi-pbiHead;elsepbiPrev-pbiNext=pbi-pbiNext;break;}pbiPrev=pbi;}/*如果是pbi是NULL则pbToFree无效*/ASSERT(pbi!=NULL);/*在释放之前破坏*pbi的内容*/memset(pbi,bGarbage,sizeof(blockinfo));free(pbi);}/*------------------------------------------------------------------*UpdateBlockInfo(pbOld,pbNew,sizeNew)**UpdateBlockInfo查出pbOld所指存储块的登录信息,然后该
本文标题:优质C程序秘诀---附录
链接地址:https://www.777doc.com/doc-6018832 .html