把布局作为一种信仰(Layout as Religion)。
                                                                                                                    --Steve McConnell(《代码大全》一书作者)
 
       在 C 语言的早期版本中,由于规定变量的赋值必须在所有变量的声明之前,因此经常能看到如下形式的代码:
           void func1() {
              int a1, a2, a3;
              double b1, b2, b3;
              double* c1;
              .....
              b1 = b2 = b3 =0.0;
              ......
             c1 = NULL;
              .....
             a1 = 3+a2;
             .....
        }

       阅读上述代码的一个麻烦之处在于,要记得所有变量第一次赋值的地方,比如上述代码中后面涉及到的 a1 的赋值就需要去前面找到它第一次出现的地方,然后依次查看其赋值信息。在《代码大全》中有个形象的比喻,早期的 C 函数变量的声明和使用风格就像在第一集电视剧中将所有的演员表都列出来,等第二集以后就不再提供演员表,如果想要找到演员的信息,只好到第一集中去找。显然,这对于观众来说相当不方便。对应到程序里,读代码的人读到这段代码也会很头疼。
       回到比方那里,一个合适的方案是,每集电视剧中出现的演员只会在本集的演员表中,这样就不用每次去第一集中去找演员的信息了。同样地,C 的后续版本以及 C++ 就采取了这种方式,它放弃了C 中原有的变量的赋值必须在所有变量的声明之后,而是可以直到使用到该变量的时候再去声明,在 C++ 中,代码的布局格式为:
      void func1() {
          double b1 = 0.0, b2 =0.0,  b3 =0.0;
          ......
          double* c1 = NULL;
          ......
          int a1 = 0, a2 =0, a3 = 0;
          a1 = 3+a2;
          .....
   }
阅读修改之后的代码, 它的层次分明了很多,总结起来就是变量初始化原则:在靠近第一次使用变量的位置声明和使用该变量[1]。
       如果考虑到调试的因素,变量初始化原则有时候也要发生些变化。如果调试过程中观察中间的运行结果,假设用 showTempResult()函数来表达,为了省去频繁的注释和取消注释代码操作,不妨使用一个变量bool isShowRes来控制这个函数的调用,按照前面提到的规则,代码的布局格式为: 
       void func1() {
          double b1 = 0.0, b2 =0.0,  b3 =0.0;
          ......
          double* c1 = NULL;
          ......
          bool isShowRes = FALSE;
          if (isShowRes == TRUE) {
               showTempResult();
          }
          int a1 = 0, a2 =0, a3 = 0;
          a1 = 3+a2;
          .....
      }
          当代码量比较少时,比如小于一个屏幕的显示(一般地,约50-150行,IBM 曾经把子程序的长度限制在50行以内 [1]),这个时候主要将程序从上往下找就可以了。但是,当该函数的代码量比较大,调试的时候就显得有些麻烦了。比如我最近用到的那个函数就有几百行,而不巧的是,要进行显示的地方位于子函数的后半段,只好每次记住显示函数的名字,进入搜索,查找到调用该函数的位置,对控制该函数调用的变量 isShowRes 的值进行修改。一个合适的方法是将该调试相关的变量提到最前面,必要的话加上相应的注释信息,每次要调用显示函数的时候直接在函数的前面进行修改,代码的布局格式为:
          void func1() {
              bool isShowRes = FALSE; //用于控制是否显示中间结果
              double b1 = 0.0, b2 =0.0,  b3 =0.0;
              ......
              double* c1 = NULL;
              ......
              if (isShowRes == TRUE) {
                  showTempResult();
              }
              int a1 = 0, a2 =0, a3 = 0;
              a1 = 3+a2;
              .....
          }

         细心的童鞋可能会问,为什么不把函数的代码行限制在一个屏幕内呢,这样就不用违背变量初始化原则了?其实,不是不想,而是不能。原因是,如果在遗留代码上进行调试,而遗留代码的该函数的代码本身就很长,将这个很长的代码行修改为较短的代码行谈何容易?即便不去考虑具体的实现细节,光想想函数的参数列表的个数就相当恐怖,当然这在理论上可以通过结构体(truct) 或者C++ 的类来克服,不过,代码的修改量仍然是巨大的。当修改的时间比代码的质量优先级更高的时候,只好牺牲代码质量来换取代码的健壮性和正确性。因此,如果是初次 Coding 的话,请尽可能遵循使用 C++ 中的类来减少函数的参数列表以及子函数的行数尽量短的原则,它会为以后的调试带来巨大的方便。
 
参考资料: 
     [1] 《代码大全(第2版)》, Steve McConnell著,金戈等译, 电子工业出版社,2006年3月:10.3 变量初始化原则 7.4 子程序可以写多长

C++中函数变量布局小结的更多相关文章

  1. 用闭包解决 js 循环中函数变量暂存问题

    需求:有一个数组,根据数组的值渲染对应的数字div,单击对应的div 在控制台打印对应的数字.如点击1,控制台打印1. 问题: 不管点击哪个值 打出来都是4 代码如下 <!DOCTYPE htm ...

  2. C++中的变量属性小结

    其实在C++中,一个变量除了数据类型以外,还有3种属性: (1)存储类别:C++中允许使用auto,static,register,extern 4种存储类别. (2)作用域:指在程序中可以使用该变量 ...

  3. python中的变量引用小结

    python的变量都可以看成是内存中某个对象的引用.(变量指向该内存地址存储的值) 1.python中的可更改对象和不可更改对象 python中的对象可以分为可更改(mutable)对象与不可更改(i ...

  4. python中的变量对象小结2

    # .变量名和数据内容是分开存储的. # .数据保存在内存中的一个位置(地址). # .变量中保存着数据在内存中的地址. # 引用就是变量中记录数据的地址. #不可变变量,重新赋值时会重新开辟一个地址 ...

  5. python中函数的参数传递小结

    “”“ 函数的参数 --必须参数,默认参数,组合参数 --函数我作为参数 --对象作为参数 --*args  可变参数 --**kwargs关键字参数 “”” def function1(a,b,*a ...

  6. 浅谈linux中shell变量$#,$@,$0,$1,$2,$?的含义解释

    浅谈linux中shell变量$#,$@,$0,$1,$2,$?的含义解释 下面小编就为大家带来一篇浅谈linux中shell变量$#,$@,$0,$1,$2的含义解释.小编觉得挺不错的,现在就分享给 ...

  7. JavaScript中函数函数的定义与变量的声明<基础知识一>

    1.JavaScript中函数的三种构造方式 a.function createFun(){ } b.var createFun=function (){ } c.var createFun=new ...

  8. c++中函数中变量内存分配以及返回指针、引用类型的思考

    众所周知,我们在编程的时候经常会在函数中声明局部变量(包括普通类型的变量.指针.引用等等). 同时,为了满足程序功能的需要,函数的返回值也经常是指针类型或是引用类型,而这返回的指针或是引用也经常指向函 ...

  9. Javascript中函数及变量定义的提升

    <html> <head> <title>函数提升</title> <script language="javascript" ...

随机推荐

  1. 使用div元素来包含内容

    在编写样式表时,经常要用到<div>元素来包含内容~~ 下面试简单的示例~ moreHigh.htm l <!DOCTYPE html> <html lang=" ...

  2. IOS本地,APNS远程推送(具体过程)

    添加本地推送 ///本地添加 -(void)addLocalPushNotification:(UIButton*)sender; { NSLog(@"%s",__FUNCTION ...

  3. UWP x:bind

    x:bind 作为win10 新特性,它好在哪?为什么要用它. 最近做UWP,对代码进行重构,对它有了一些了解. 先说优点: 1.性能高,内存小(相比传统的binding) 没图没真相,我先上2张图. ...

  4. JS截字符串处理数字,汉字,英文问题

    <script> function suolve( str,sub_length ){ var temp1 = str.replace(/[^\x00-\xff]/g,"**&q ...

  5. java web.xml配置详解

    1.启动一个WEB项目的时候,WEB容器会去读取它的配置文件web.xml,读取<listener>和<context-param>两个结点. 2.紧急着,容创建一个Servl ...

  6. js函数封装

    1.随机数 <script> function rnd(n,m){ return parseInt(Math.random()*(m-n)+n); } var a=rnd(45,47); ...

  7. 纯CSS实现二级下拉导航菜单

    这是一款纯CSS菜单,二级下拉导航效果,是最简洁的CSS导航菜单,兼容性也很棒,IE7/8.火狐等都支持,而且它还是学习CSS菜单编写的典型教程,让你学会很多CSS技巧. 运行效果截图如下: < ...

  8. CodeForces 103D 分块处理

    题目链接:http://codeforces.com/problemset/problem/103/D 题意:给定一个长度为n的序列.然后q个询问.每个询问为(a,b),表示从序列第a项开始每b项的加 ...

  9. 比管理员(administrator)更高权限的TrustedInstaller

    http://www.gezila.com/tutorials/9664.html 什么是TrustedInstaller管理权限 ?好多朋友都在使用Windows7系统.在使用过程中,有些朋友在删除 ...

  10. iOS 之 Cocoapods安装

    进入正题前,先来点前奏:了解cocoapods是某天看一个博客,那时才明白原来写项目不用一个个将三方库拷进项目里啊,惊讶的我是一塌糊涂的啊...(原谅我那时还没进入过正规的IT公司....好多你们自然 ...