程序结构的7个证明原理

2008-04-09 04:05:43来源:互联网 阅读 ()

新老客户大回馈,云服务器低至5折

  程序结构应遵循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中也混入了错误。

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:某女生编的一经典c语言程序

下一篇:常用手册