C潜规则篇之代码书写

来源:互联网 发布:通达信编程 编辑:程序博客网 时间:2024/05/01 21:13

    代码书写过程中一些不好的习惯,也可能导致语法错误,代码丢失等问题,使得编码和维护的效率低下。下面几点虽然都是一些很细节的地方,但细节决定命运,编程中从细节处完善,养成好的习惯,也可以长久受益。

修改前手动备份

    修改代码时经常碰到这种情况,对某模块做修改,改了一半发现原来构想错误,想退回原点,却不幸忘记刚才修改了哪些地方。辛苦大半天,回不到解放前。即使现在有代码管理系统,一些小规模的调试修改前还是应自己备份。

匹配符号成对写

    C语言中一些符号如:{}, (), [], “”,/**/要求有始有终,保证前后匹配。如果按习惯从左到右顺序写,一些复杂嵌套表达式的语法检查就比较麻烦。好办法是先成对写好符号模板,再往里填内容。如表达式:if(((a > 100) && (a < 200 )) || ( b % 2 )),式子很长,嵌套层次多,检查括号匹配让人头晕,再复杂更不用说了。从左到右顺序写,写到右边后半部分还要不断回头数着要加几个另一半括号,写完还得检查,效率低又易出错。改为下面书写步骤:

    1. if()

    2. if(() || ())

    3. if((()&&())||(b%2))

    4. if(((a>100)&&(a<200))||(b%2))

    这种方式写完后不用检查就一定正确。同样,匹配函数成对写。C中一些资源管理类函数需要成对出现,比如:malloc/free, init/uninit, fopen/fclose等,开始就写好也可以防止因忘记释放而产生资源泄漏。

先写;

    下面程序片段中:

    struct x{

      int a

    }

    f() {  ...  }

    紧挨着函数f()前的}号后遗漏了;分号,结果就变成声明函数f(),返回值类型是struct x。如果f()前有分号,f()默认返回整型值,两种情况意义完全不同。为防止类似bug,定义struct时先完成包括;在内的模板,再写结构体内容。即:struct x {…… }//一次写全。

严格按模板,不省略{}()

    省略{}()不是好习惯,多重if elseswitch case语句中,省略{}后往往语法正确,但功能与预想相差很远,导致代码能通过编译器检查却引入了bug。如悬挂else: 

    if (x == 0)

        if (y == 0) error();

    else

   {

      z = x + y;

    }

    本意:x分为0和非0两种情况,x0时,如果y也等0,调用函数error,否则不处理;x不等0时,把xy的和赋给z而上面代码实现的功能与设想完全不同。Celse始终与最近的未匹配if结合,实际逻辑就成为:

    if (x == 0) {

      if (y == 0) error();

      else {  z = x + y;    }

    }

    这里else和第二个if结合了,程序逻辑偏离原意,要体现原本意图,应:

    if (x == 0) {

      if (y == 0) error();

    } else {

      z = x + y;

    }

    这样第二个if被括号封装,else才会与第一个if结合。之前就少写个{},结果因小失大。江湖传言,类似错误曾导致NASA的一次航天事故。即使语法语义正确,省略{}还会增加代码修改时引入错误的风险,如:

    if(cMychar <= ‘Z’)

      printf(“This is a letter \n”);

    else

      printf(“This is not a letter \n”);

    后来者觉得要在else后增加额外功能,于是顺手添加了一个函数调用,变成:

    if(cMychar <= ‘Z’)

      printf(“is a letter \n”);

    else

      printf(“not a letter \n”);

      added_function();

    受原代码误导,直接插入新增语句,误认为它们仍属同一模块。但缺少{}束缚,新增语句会把added_function();挤出else范围。错误根源还是省略了{}

 

    总之,按正规流程书写代码有助于在开始就把一些小问题消灭于无形之中。

0 0