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" ...
随机推荐
- stack.sh failing giving error "g-api did not start"
same issue i faced , tried with ./unstack.sh and ./clean.sh also but couldn't fix the issue.Followin ...
- MySQL 5.5安装记录
安装gnake ./configure && gmake && gmake install 安装ncurses-devel yum install -y ncurses ...
- 《C#本质论》读书笔记(16)构建自定义集合
16.1 更多集合接口 集合类(这里指IEnumerable层次结构)实现的接口层次结构 16.1.1 IList<T>与IDictionary<TKey,TValue> 字典 ...
- linux下bus、devices和platform的基础模型
转自:http://blog.chinaunix.net/uid-20672257-id-3147337.html 一.kobject的定义:kobject是Linux2.6引入的设备管理机制,在内核 ...
- java多线程编程
一.多线程的优缺点 多线程的优点: 1)资源利用率更好2)程序设计在某些情况下更简单3)程序响应更快 多线程的代价: 1)设计更复杂虽然有一些多线程应用程序比单线程的应用程序要简单,但其他的一般都更复 ...
- kNN算法python实现和简单数字识别
kNN算法 算法优缺点: 优点:精度高.对异常值不敏感.无输入数据假定 缺点:时间复杂度和空间复杂度都很高 适用数据范围:数值型和标称型 算法的思路: KNN算法(全称K最近邻算法),算法的思想很简单 ...
- HDU3333 Turing Tree(线段树)
题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=3333 Description After inventing Turing Tree, 3x ...
- mac系统下mysql开机启动总是3307
修改了mysql的my.cnf可还是不行,启动后就是3307,必须关掉再启动. 觉得可能是mac系统在哪里写死了开机启动项. http://queforum.com/mysql/1012987-mys ...
- H5移动APP开发 细节详解(转)
工作了有一段时间,基本上都在搞移动端的前端开发,工作的过程中遇到过很多问题,bug的解决方案,记录下来,以便后用!!!内容并不是很全,以后每遇到一个问题都会总结在这里,分享给大家! 一.meta标签相 ...
- [机器学习] 虚拟机VMware中使用Ubuntu的联网问题
在VMware中安装Ubuntu要解决两个问题: 1.VMware Tools安装使用 2.Ubuntu联网的虚拟机设置 1.VMware Tools安装 它的作用就是使用户可以从物理主机直接往虚拟机 ...