法式构造应遵照7个证明原理,以确保法式的准确性、强健性、乖巧性、可重用和可读性等。
1. 单纯原理
所谓单纯性原理是指变量或指针等的利用遵照单一化的原则,即为差别的用处利用差别的变量或指针。摘用了单纯原理,法式就能够明白的反映现实的问题。
如下面的法式,从一个文件中读进数据放到另一个文件中:
FILE* fp = NULL;
fp = fopen(m_strSrcFilePath, “r“);
/* 读数据 */
fclose(fp);
/* 对数据停止处置 */
fp = fopen(m_strDesFilePath, “w“);
/* 写数据 */
统一个指针变量fp在一个子法式中被用来做为两个差别文件的指针,固然没有错误,但随便形成对fp理解困难,所以更好如许:
FILE* fpSrc = NULL; /* 源文件 */
FILE* fpDes = NULL; /* 目标文件 */
fpSrc = fopen(m_strSrcFilePath, “r“);
/* 读数据 */
fclose(fp);
/* 对数据停止处置 */
fpDes = fopen(m_strDesFilePath, “w“);
/* 写数据 */
2. 同型原理
同型原理是指不异逻辑的处所应该有不异的构造;能复用的代码就不要重写,用宏或者子法式实现。
例如下面那两个轮回:
for(i = 0; i m_aLinkMan.GetSize(); i++);
for(i = 0; i = m_aLinkMan.GetSize()-1; i++);
认真一看,会发现那两个轮回其实是一样的,但对它们为什么形式差别会感应难懂,引起阅读的障碍。
3. 对称原理
对称原理是指成对的操做应该成对地呈现,而且呈现在对称的位置上。好比:内存的申请与释放、文件的翻开与封闭、if语句能否需要响应的else语句等。各系统、构成成分或模块都应遵照对称原理。
在Linux下,对称原理次要表示为以下几点:
malloc等分配内存的函数和free函数必需成对呈现,并且必需包管释放掉指针不再被利用。
open/fopen等翻开文件的函数和close/fclose函数必需成对呈现,并且必需包管封闭的文件描述符或者流指针不再被利用。
利用signal或者sigaction设置信号处置法式时,应该先保留旧的信号处置法式,等处置完毕停止恢复。
还有其他一些函数也必需成对利用,如mmap/munmap,pthread_mutex_init/ pthread_mutex_destroy,sem_init/sem_destroy等等。
关于法式中的模块、函数,若有需要,也应该连结对称。
4. 条理原理
条理原理是外形的条理美原理。例如,意识到事物的主从关系,前后关系,本末关系等条理关系,逃求事物应有的形态。必需使各个条理详尽化、数据笼统化。条理的规定要彻底。
例若有如下代码:
struct p1 {};
struct p2 {
struct p1 *pp1;
struct p2 *pp2;
能够看出构造体p1和p2之间又很明显的条理关系,分配内存时,应先为pp2分配内存,然后为pp2-pp1分配内存;释放时,应该先释放pp2-pp1的内存,然后再释放pp2的内存。
再例如,停止多线程编程时,经常会需要停止互斥或者是信号量操做。那么应该先挪用pthread_mutex_lock设置mutex停止互斥,然后再挪用sem_wait停止信号量操做。若是挨次弄反了,则会引进一个race condition,从而可能产存亡锁。
以上的例子只是比力简单的情状,在法式中可能存在十分冗杂的情状,要重视判别。
5. 线性原理
线性原理是指事物的外形是由曲线描画出来的。例如,某个功用,是由几个功用的堆叠组合加以实现的。因而,在法式中应该尽量不利用GOTO,SCHEDULE,POST/WAIT等功用。
6. 明证原理
逻辑的明证性原理,即应该勤奋的阐明一些不太肃清的逻辑,而且使其具有说服力。
实例:查抄领受到的数据中带有的数据序号的持续性。数据序号是用2个byte表达的,从0起头,之后每个递增1,到达 0xffff后,再重头起头。还有,在0xffff上加上1就会酿成0。
* nowseq : 承受通知后的数据编号
* oldseq : 承受通知前的数据编号
* 已承受通知的数据编号,不等于承受通知前的数据编号加一,或者
* 被通知前的数据的编号为0xffff,如今已承受通知的编号不为0
if ((nowseq != oldseq + 1) || (oldseq == 0xffff nowseq != 0 )) {
错误处置;
那个法式似乎是准确的,可是,它有良多否认形的逻辑式,所以比力难以理解。起首,用必定形式(也就是一般的前提)表达,再加上”!”,做为错误的前提,如许做能够使人安心。根据如许的做法操做,法式会构成下述情状,比本来的法式易懂。
if (!((nowseq == oldseq + 1) || (nowseq == 0 oldseq == 0xffff))) {
错误处置;
原法式中有逻辑错误。也就是, nowseq是0,oldseq是0xffff的时候,称心了if的第一个前提项的nowseq!=oldseq+1,所以固然是准确的情状却被当成了错误。
7. 平安原理
平安原理是指意识到一定性的原理。例如,漠视没有一定性或者迷糊不清的处所,用平安的办法、思惟来设想。
举例,有挪用法式(Caller)和被挪用法式(Callee),两者间挪用接口用的参数list是P。Caller没有把P内的Pi域中的初值设定为’0’,所以Callee侧是反常操做。
那个毛病是在批改法式的时候产生的,查询拜访毛病的原因,发现原法式中也有不异的挪用部门,那里是准确的代码。也就是说,把P全数清为0,(由此,Pi域的初值就设定为’0’ ),然后挪用Callee。
批改法式,通过逃加一个挪用,批改的负责人模仿先前的挪用部门,停止了编码,认为把P全体清为0是没有需要的,(可能是想把法式的步调削减),于是,P全体清0的步调被省略了。可是,不幸的是, Pi中也混进了错误。
那个例子中的问题是没有照移准确操做的代码。固然曾经把它清为0,可是不克不及包管之后它不断为0。利用前,把参数list清为0,是coding的根本原则。如许做是平安的,所以契合平安原理。
原文做者所属博客:乐走天边