4.1 保持较小的作用域。
保持较小的作用域有助于避免一些难以发现的错误。
C++支持在for循环和if语句中直接声明变量,如:
for (int i=0; i<100;i++){}
if (bool b = func() ) {}
其中i和b的作用域从被声明的点开始,直到 } 结束。
4.2 不要在一个作用域和它外围的作用域里采用同样的名字。
在一个作用域和它外围的作用域里采用同样的名字会造成名字遮蔽,即外围的名字被内部作用域的名字遮蔽,人们很容易没有注意某个名字被遮蔽了,所以会造成一些隐蔽的错误。
4.3 在一个声明中声明一个名字。
例如int* p, q; 是指int* p; int q; 而不是int* p; int* q; int* p, q;这种结构不利于阅读,因此应该避免。
4.4 让常用的和局部的名字比较短,让不常用的和全局的名字比较长。
选择好的名字是一种艺术。较大的作用域的名字应该相对比较长且更加明确,如textParser、intMatrix。在很小的作用域使用很短且熟悉的名字,如i、x、tmp。常用的名字比较短,书写方便,不常用的名字比较长这种做法也很有价值。
4.5 避免看起来类似的名字。
如只是大小写不同的名字,count和Count。或者大写的O和零0,小写的L(l)和一(1)都很难分辨,应该避免。一些代码分析工具如CodeWizard会对它们提出警告。
4.6 维持某种统一的命名风格。
应该选择一种统一的命名风格。如宏定义和枚举大写,用下划线分隔单词等。这样可以提高代码的可读性。
4.7仔细选择名字,反映其意义而不是反映其实现方式。
例如phone_book就比number_list要好,即使你的电话号码实际存放在list里。请仔细选择那些重要的名字,否则几个月后自己写的代码也会让你困惑。
4.8如果所用的内部类型表示某种可能变化的值,请用typedef为它定义一个有意义的名字。
例如我们想用float去表示温度,那么用typedef会清晰的表明含义。typedef float Temperature。Temperature temp;
4.9 用typedef为类型定义同义词,用枚举或类定义新类型。
typedef是为类型定义同义词,而不是定义新的类型。C++里只有枚举或类是用户定义类型,可以用来定义新类型。
4.10 切记每个声明中都必须描述一个类型(没有“隐式的int“)
例如const c = 7;C和C++的早期版本将int作为没有明确声明的类型。这种隐式的int会导致许多微妙错误。
4/11 避免有关字符数值的不必要假设。
一个字符表示的是C++程序运行的机器上的字符集中该字符的整数值。如果在一台使用ASCII字符集的机器上,’0’的值就是48。在非ASCII字符集的机器上如EBCDIC字符集,’0’的值是240。char的大小通常为8位,但标准并没有规定它的大小,只是保证至少有8位。
4.12避免有关整数大小的不必要假设。
int的大小是由实现确定的,典型情况下是32位。short int至少有16位,long int至少有32位。
4.13避免有关浮点类型表示范围的不必要假设。
浮点类型有float、double、long double,它们的大小由实现确定。
4.14 优先使用普通的int而不是short int 或者long int
int大小由实现选择,采用在给定的计算机上最适合存储和操作整数的类型,通常是一个32位的机器字。
4.15 优先使用double而不是float 或者long double
浮点类型有float、double、long double,意义由实现确定。对浮点运算的深入理解能帮助选择合适的类型,或者一般情况下选择double就可以。
4.16 优先使用普通的char而不是signed char 或者unsigned char
char可能是有符号的,也可能是无符号的。这三种char类型的变量可以相互赋值,但可能导致无定义的结果。例如,char c; signed char sc; unsigned char uc;
c = 255; // 如果char有符号且为8位,则由实现定义
c = sc; // 可以
c = uc; //如果普通char有符号且uc值过大,则由实现定义
sc = uc; //uc值过大,则由实现定义
uc = sc;//可以, 转换到unsigned值
sc = c; ///如果普通char无符号且c值过大,则由实现定义
uc = c; //可以, 转换到unsigned值
如果始终采用普通char, 这些问题都不会出现。
4.17 避免做出有关对象大小的不必要假设。
C++对象的大小是用char的大小的倍数表示的, 按照定义,char的大小为1。
基本类型大小的性质为:
1=sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long)
1 <= sizeof(bool) <= sizeof(long)
sizeof(char) <= sizeof(wchar_t) <= sizeof(long)
sizeof(float) <= sizeof(double) <= sizeof(long double)
sizeof(N) = sizeof(signed N) = sizeof(unsigned N)
4.18 避免无符号算术。
通过将变量声明为unsigned而保证某些值始终为正的企图常常被隐含的类型转换规则破坏。如有这样的定义,unsigned int ui; int i; 如果恰好ui的值为0 且 i的值为-1,那么ui+i等于多少? -1?结果将是unsigned int类型的最大值。因为i会被提升到unsigned int,然后再与ui相加。 如果是两个普通的int相加就不会有问题。
4.19 应该带着疑问去看待从signed到unsigned,或者从unsigned到signed的转换。
如果目标类型是unsigned,结果值就是从原值中取出正好等于目标类型所需要的那么多位, 可能会发生截断。 如unsigned char uc = 1023;高位被截断, uc的值为255,即11111111。
如果目标类型是signed,如果源值在结果类型中可以表示,则值不变,否则结果值由实现定义。 如signed char sc = 1023;//实现定义
4.20应该带着疑问去看待从浮点到整数的转换。
浮点到整数转换,小数部分将被丢掉,也就是截断。如果转换结果无法在目标类型里表示,则结果无定义。 如:int i = 2.7;//i变为2
char b = 2000.7;// 对8位char无定义,2000不能在8位char里表示
4.21应该带着疑问去看待向较小类型的转换,如将int转到char。
向较小类型的转换,如将int转到char, 可能发生截断, 也可能导致无定义的行为, 参考4.19