C++中函数变量布局小结
把布局作为一种信仰(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++中函数变量布局小结的更多相关文章
- 用闭包解决 js 循环中函数变量暂存问题
需求:有一个数组,根据数组的值渲染对应的数字div,单击对应的div 在控制台打印对应的数字.如点击1,控制台打印1. 问题: 不管点击哪个值 打出来都是4 代码如下 <!DOCTYPE htm ...
- C++中的变量属性小结
其实在C++中,一个变量除了数据类型以外,还有3种属性: (1)存储类别:C++中允许使用auto,static,register,extern 4种存储类别. (2)作用域:指在程序中可以使用该变量 ...
- python中的变量引用小结
python的变量都可以看成是内存中某个对象的引用.(变量指向该内存地址存储的值) 1.python中的可更改对象和不可更改对象 python中的对象可以分为可更改(mutable)对象与不可更改(i ...
- python中的变量对象小结2
# .变量名和数据内容是分开存储的. # .数据保存在内存中的一个位置(地址). # .变量中保存着数据在内存中的地址. # 引用就是变量中记录数据的地址. #不可变变量,重新赋值时会重新开辟一个地址 ...
- python中函数的参数传递小结
“”“ 函数的参数 --必须参数,默认参数,组合参数 --函数我作为参数 --对象作为参数 --*args 可变参数 --**kwargs关键字参数 “”” def function1(a,b,*a ...
- 浅谈linux中shell变量$#,$@,$0,$1,$2,$?的含义解释
浅谈linux中shell变量$#,$@,$0,$1,$2,$?的含义解释 下面小编就为大家带来一篇浅谈linux中shell变量$#,$@,$0,$1,$2的含义解释.小编觉得挺不错的,现在就分享给 ...
- JavaScript中函数函数的定义与变量的声明<基础知识一>
1.JavaScript中函数的三种构造方式 a.function createFun(){ } b.var createFun=function (){ } c.var createFun=new ...
- c++中函数中变量内存分配以及返回指针、引用类型的思考
众所周知,我们在编程的时候经常会在函数中声明局部变量(包括普通类型的变量.指针.引用等等). 同时,为了满足程序功能的需要,函数的返回值也经常是指针类型或是引用类型,而这返回的指针或是引用也经常指向函 ...
- Javascript中函数及变量定义的提升
<html> <head> <title>函数提升</title> <script language="javascript" ...
随机推荐
- 2.EasyUI学习总结(二)——easyloader分析与使用(转载)
本文转载自:http://www.cnblogs.com/haogj/archive/2013/04/22/3036685.html 使用脚本库总要加载一大堆的样式表和脚本文件,在easyui 中,除 ...
- 【python】装饰器
来源:廖雪峰 看了好多次装饰器,发现还是廖老师讲得好,能让我看懂..... 下面是一段装饰器代码 @log def now(): " 它的含义等价于 def now(): " no ...
- IE 中单元格的 colspan 属性在某些情况下会影响 TABLE 元素的自动布局
今天在写一个jsp页面时,遇到一个如下的问题:在一个table中写了如下内容,table中定义了4列,在firefox中能正常显示,而在ie8中,显示不正常, 如下如图1:第二,三,四列宽度发生变化, ...
- 【XLL 框架库函数】 TempBool/TempBool12
创建一个包含了 Boolean 类型的 TRUE 或 FALSE 的 XLOPER/XLOPER12 LPXLOPER TempBool(int b); LPXLOPER12 TempBool12(i ...
- HBASE列族不能太多的真相 (一个table有几个列族就有几个 Store)
HRegionServer内部管理了一系列HRegion对象,每个HRegion对 应了table中的一个region,HRegion中由多 个HStore组成.每个HStore对应了Table中的一 ...
- centos下查看最大Socket连接数
使用命令ulimit -a查看,其中open files就是最大连接数,一般情况下web服务器最大连接数的设置不能超过它 修改最大连接数:vi /etc/security/limits.conf 文件 ...
- [译]:Orchard入门——给网站添加页面
原文链接:Adding Pages to Your Site 注:内容为官方文档翻译,本人遇到的page中间是布局,而非官网的body--但此内容可以在内容定义里自行修改(本文不做介绍) 在创建Orc ...
- 前台处理json字符串的几种方法(转)
原文地址http://www.css88.com/archives/3919 比如我有两个变量,我要将a转换成字符串,将b转换成JSON对象: var a={"name":&quo ...
- CentOS两台服务器利用scp拷贝文件
yum install -y openssh-clients scp -r -P 26611 /usr/local/ssdb-20160518/ root@10.10.6.199:/usr/local ...
- iscrolljs 看API 回顾以前开发中失误
今天有空 细致的看看iscrolljs api 发现自己以前的几个失误是没看api造成的 失误1 页面a操作 影响了页面b的滚动条 api 解释: options.bindToWrapper The ...