《高质量C++C编程指南》纠错与拾遗(一)

使用C++/C编程的程序员,几乎都看过林锐博士写的《高质量C++C编程指南》这篇百页经书,并且通过阅读这篇百页经书,受益匪浅。我也是这篇文章的受益者。通过这篇百页经书,我学到很多知识,也给于了我深入学习C++的动力。

最近,偶得机会,再次拜读林锐博士的《高质量C++C编程指南》,发现里面有些观点颇有争议,本文作者对这些观点进行的了考证,整理,汇总,形成了此文档,这里绝无批驳,贬低《高质量C++C编程指南》之意,其目的有二,一:阐述本文作者对《高质量C++C编程指南》的一些观点,如果这些观点能够对读者学习C++起到的启迪作用,作者就万分欢喜了,2:见证作者的C++学习之路。如果您在阅读此文时,发现任何问题,包括文字,符号,观点,用例,欢迎您和我交流,我将及时更正,谢谢。

所谓纠错:是本文作者对林锐博士的《高质量C++C编程指南》中有争议的技术,观点做进一步的考证和整理。
    所谓拾遗:是本文作者对林锐博士的《高质量C++C编程指南》中点到为止的技术,观点,做一些简短的补充和解释。
       林锐博士的《高质量C++C编程指南》是一本很好的编程规范手册,在具体项目中,具体环境中这些规范并不一定是最好的,但是已经足够好,所以我不想找这些规范的错误,不想对这些规范作更多的解释。本文的重点将放在对技术的讨论上,此乃一家之言,切勿较真。      

1:尽量使用小写的bool类型

关于BOOL类型的if判断在林锐博士的《高质量C++C编程指南》的4.3.1 布尔变量与零值比较如下说明



【规则4-3-1不可将布尔变量直接与TRUE、FALSE或者1、0进行比较。



根据布尔类型的语义,零值为“假”(记为FALSE),任何非零值都是“真”(记为TRUE)。TRUE的值究竟是什么并没有统一的标准。例如Visual C++ 将TRUE定义为1,而Visual Basic则将TRUE定义为-1。

假设布尔变量名字为flag,它与零值比较的标准if语句如下:

if (flag)   // 表示flag为真
     if (!flag)  // 表示flag为假

其它的用法都属于不良风格,例如:

    if (flag == TRUE)
         if (flag == 1 )
         if (flag == FALSE) 

在这里首先说明的一点是,在标准C/C++中没有内置大写的BOOL,TRUE,FALSE关键字,这些关键字是VC的扩展,在windef.h文件中我们找到如下的声明

typedef int                 BOOL;
         #ifndef FALSE
         #define FALSE               0
         #endif

#ifndef TRUE
         #define TRUE                1
         #endif

可见在VC下BOOL类型是int型的宏,而TRUE,FALSE分别代表0,1。通过下面的例子更能说明问题
         cout << "sizeof(BOOL): "<<sizeof(BOOL) << endl; // 值为4
         cout << "sizeof(TRUE): "<<sizeof(TRUE) << endl; // 值为4
         cout << "sizeof(FALSE): "<<sizeof(FALSE) << endl; // 值为4

林锐博士博士在文章中提到“TRUE的值究竟是什么并没有统一的标准,Visual C++ 将TRUE定义为1,而Visual Basic则将TRUE定义为-1”其实我认为在此举例并不能很好说明问题,因为Visual Basic是并没有采用C/C++编程语言,所以无法例证TRUE的声明。当把BOOL定义为int,TRUE定义为1,FALSE定义为0时,会引发诸多问题,比较典型的集中情况如下

1:不会存在如下类型的函数重载

void fun(BOOL);
         void fun(int);
      此时BOOL是int型,编译器并不认为上面两个函数是重载,而认为是重复定义。
2:当定义void fun(int)函数时,出现以下情况编译器都将按int型处理
        int i = 5;
        int j = 3;
        BOOL bState = FALSE;
        fun(i<j);
        fun(bState);

       3:++,--问题

       这种问题更为隐秘,当我们定义BOOL state(TRUE);如果程序代码很长,并且复杂,那么我们无意中执行了—state操作,编译器不会提示任何错误,并且我们的if判断也不会出现任何判断问题。这条隐藏的bug将是非常难找的。

       标准C/C++的中内置的关键字是小写的bool,true,false,如果我们采用bool类型可以很好避免如上提到的问题。所以,在平时编程时尽量使用bool类型而不是BOOL类型。

       有的平台上是如下定义BOOL类型的
       enum BOOL {FALSE=0,TRUE};采用这种方法,解决问题并不彻底。读者可以根据上面例子,判断这种方式的优缺点。

       关于bool类型在if语句中的判断,如果我们在编写一个跨平台,并且不想受C++语言的发展对程序代码的影响,在if判断时最好采用

        if (flag == false)
    if (flag == true)  

方式。因为C++没有规定true的值为什么,同样也就没有规定false的值为什么,只是编译器一般的做法是把false定义为0(这里的0并不是int中的0,它可能是二进制0,也可以能是一个字节中的0),而把非false的值,定义为true,如果将来C++明确规定false为1,ture为2,那么按照原来的写法,所有的if语句都要修改,这种说法可能有些杞人忧天,至少说明,将来可能会出现这种情况。所以最好采用

        if (flag == false) 
    if (flag == true)  

这种方式。
 

时间: 2024-09-11 21:38:03

《高质量C++C编程指南》纠错与拾遗(一)的相关文章

高质量C++/C编程指南

              高质量C++/C编程指南         文件状态 [ ] 草稿文件 [√] 正式文件 [ ] 更改正式文件 文件标识:   当前版本: 1.0 作    者: 林锐 博士 完成日期: 2001年7月24日     版本历史   版本/状态 作者 参与者 起止日期 备注 V 0.9 草稿文件 林锐     2001-7-1至 2001-7-18 林锐起草 V 1.0 正式文件 林锐     2001-7-18至 2001-7-24 朱洪海审查V 0.9, 林锐修正草稿

高质量C++/C编程指南-第10章-类的继承与组合(2)

10.2 组合l [规则10-2-1]若在逻辑上A是B的"一部分"(a part of),则不允许B从A派生,而是要用A和其它东西组合出B. 例如眼(Eye).鼻(Nose).口(Mouth).耳(Ear)是头(Head)的一部分,所以类Head应该由类Eye.Nose.Mouth.Ear组合而成,不是派生而成.如示例10-2-1所示. class Eye {public: void Look(void); };class Nose {public: void Smell(void);

高质量C++/C编程指南-第11章-其它编程经验(2)

11.1.3 const成员函数 任何不会修改数据成员的函数都应该声明为const类型.如果在编写const成员函数时,不慎修改了数据成员,或者调用了其它非const成员函数,编译器将指出错误,这无疑会提高程序的健壮性. 以下程序中,类stack的成员函数GetCount仅用于计数,从逻辑上讲GetCount应当为const函数.编译器将指出GetCount函数中的错误. class Stack { public: void Push(int elem); int Pop(void); int

高质量C++/C编程指南-第7章-内存管理(1)

欢迎进入内存这片雷区.伟大的Bill Gates 曾经失言: 640K ought to be enough for everybody - Bill Gates 1981 程序员们经常编写内存管理程序,往往提心吊胆.如果不想触雷,唯一的解决办法就是发现所有潜伏的地雷并且排除它们,躲是躲不了的.本章的内容比一般教科书的要深入得多,读者需细心阅读,做到真正地通晓内存管理. 7.1内存分配方式内存分配方式有三种: (1) 从静态存储区域分配.内存在程序编译的时候就已经分配好,这块内存在程序的整个运行

高质量C++/C编程指南-第4章-表达式和基本语句

读者可能怀疑:连if.for.while.goto.switch这样简单的东西也要探讨编程风格,是不是小题大做? 我真的发觉很多程序员用隐含错误的方式写表达式和基本语句,我自己也犯过类似的错误. 表达式和语句都属于C++/C的短语结构语法.它们看似简单,但使用时隐患比较多. 本章归纳了正确使用表达式和语句的一些规则与建议. 4.1 运算符的优先级 C++/C语言的运算符有数十个,运算符的优先级与结合律如表4-1所示.注意一元运算符 + - * 的优先级高于对应的二元运算符. 优先级 运算符 结合

高质量C++/C编程指南-第7章-内存管理(5)

7.9 内存耗尽怎么办?如果在申请动态内存时找不到足够大的内存块,malloc和new将返回NULL指针,宣告内存申请失败.通常有三种方式处理"内存耗尽"问题. (1)判断指针是否为NULL,如果是则马上用return语句终止本函数.例如: void Func(void) { A *a = new A; if(a == NULL) { return; } - } (2)判断指针是否为NULL,如果是则马上用exit(1)终止整个程序的运行.例如: void Func(void) { A

高质量C++/C编程指南-第6章-函数设计(3)

对于相加函数,应当用"值传递"的方式返回String对象.如果改用"引用传递",那么函数返回值是一个指向局部对象temp的"引用".由于temp在函数结束时被自动销毁,将导致返回的"引用"无效.例如: c = a + b; 此时 a + b 并不返回期望值,c什么也得不到,流下了隐患. 6.3 函数内部实现的规则不同功能的函数其内部实现各不相同,看起来似乎无法就"内部实现"达成一致的观点.但根据经验,我们可

高质量C++/C编程指南-第11章-其它编程经验(1)

11.1 使用const提高函数的健壮性看到const关键字,C++程序员首先想到的可能是const常量.这可不是良好的条件反射.如果只知道用const定义常量,那么相当于把火药仅用于制作鞭炮.const更大的魅力是它可以修饰函数的参数.返回值,甚至函数的定义体. const是constant的缩写,"恒定不变"的意思.被const修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性.所以很多C++程序设计书籍建议:"Use const whenever you

高质量C++/C编程指南-第10章-类的继承与组合(1)

对象(Object)是类(Class)的一个实例(Instance).如果将对象比作房子,那么类就是房子的设计图纸.所以面向对象设计的重点是类的设计,而不是对象的设计. 对于C++程序而言,设计孤立的类是比较容易的,难的是正确设计基类及其派生类.本章仅仅论述"继承"(Inheritance)和"组合"(Composition)的概念. 注意,当前面向对象技术的应用热点是COM和CORBA,这些内容超出了C++教材的范畴,请阅读COM和CORBA相关论著. 10.1