法式构造的7个证明原理

3个月前 (11-26 18:54)阅读2回复0
dyyh
dyyh
  • 管理员
  • 注册排名7
  • 经验值131860
  • 级别管理员
  • 主题26372
  • 回复0
楼主

  法式构造应遵照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的根本原则。如许做是平安的,所以契合平安原理。

原文做者所属博客:乐走天边

0
回帖

法式构造的7个证明原理 期待您的回复!

取消