上篇请看:C++编程思想重点笔记(上)
宏的好处与坏处
宏的好处:#与##的使用
三个有用的特征:字符串定义、字符串串联和标志粘贴。
字符串定义的完成是用#指示,它容许设一个标识符并把它转化为字符串,然而字符串串联发生在当两个相邻的字符串没有分隔符时,在这种情况下字符串组合在一起。在写调试代码时,这两个特征是非常有效的。
#define DEBUG(X) cout<<#X " = " << X << endl
上面的这个定义可以打印任何变量的值。
我们也可以得到一个跟踪信息,在此信息里打印出它们执行的语句。#define TRACE(S) cout << #S << endl; S
#S
定义了要输出的语句。第2个S重申了语句,所以这个语句被执行。当然,这可能会产生问题,尤其是在一行for循环中。for (int i = 0 ; i < 100 ; i++ )
TRACE(f(i)) ;
因为在TRACE( )宏里实际上有两个语句,所以一行for循环只执行第一个。
for (int i = 0 ; i < 100 ; i++ )
cout << "f(i)" << endl;
f(i); // 第二条语句脱离了for循环,因此执行不到
解决方法是在宏中用逗号代替分号。
标志粘贴在写代码时是非常有用的,用##表示。它让我们设两个标识符并把它们粘贴在一起自动产生一个新的标识符。例如:
#define FIELD(A) char *A##_string;int A##_size
此时下面的代码:
class record{
FIELD(one);
FIELD(two);
FIELD(three);
//...
};
就相当于下面的代码:
class record{
char *one_string,int one_size;
char *two_string,int two_size;
char *three_string,int three_size;
//...
};
宏的不好:容易出错
下面举个例子即可说明:#define band(x) (((x)>5 && (x)<10) ? (x) :0)
int main() {
for(int i = 4; i < 11; i++) {
int a = i;
cout << "a = " << a << "\t";
cout << "band(++a)" << band(++a) << "\t";
cout << "a = " << a << endl;
}
return 0;
}
输出:
a = 4 band(++a)0 a = 5
a = 5 band(++a)8 a = 8
a = 6 band(++a)9 a = 9
a = 7 band(++a)10 a = 10
a = 8 band(++a)0 a = 10
a = 9 band(++a)0 a = 11
a = 10 band(++a)0 a = 12
存储类型指定符
常用的有static
和extern
。
不常用的有两个:一是auto
,人们几乎不用它,因为它告诉编译器这是一个局部变量,实际上编译器总是可以从 变量定义时的上下文中判断出这是一个局部变量。所以auto
是多余的。还有一个是register
,它也是局部变量,但它告诉编译器这个特殊的变量要经常用到,所以编译器应该尽可能地让它保存在寄存器中。它用于优化代码。各种编译器对这种类型的变量处理方式也不尽相同,它们有时会忽略这种存储类型的指定。一般,如果要用到这个变量的地址,register
指定符通常都会被忽略。应该避免用register
类型,因为编译器在优化代码方面通常比我们做得更好。位拷贝(bitcopy)与值拷贝的区别(很重要)
由1个例子来说明:一个类在任何时候知道它存在多少个对象,可以通过包含一个static成员来做到,如下代码所示:#include <iostream>
using namespace std;
class test