C++可以用const定义常量,也可以用#define定义常量,但是前者比后者有更多的有点:
1、const常量有数据类型,而宏常量没有数据类型。编译器可以对const进行类型安全检查,而对后者只进行字符替换,没有类型安全检查,并且在字符替换中可能会产生意料不到的错误(边际效应)。
2、有些集成化的调试工具可以对const常量进行调试,但是不能对宏常量进行调试。在C++程序中只使用const常量而不适用宏常量,即const常量完全取代宏常量。
3、编译器处理方式不同
define宏是在预处理阶段展开。
const常量是编译运行阶段使用。
4、存储方式不同
define宏仅仅是展开,有多少地方使用,就展开多少次,不会分配内存。
const常量会在内存中分配(可以是堆中也可以是栈中)。
问题2:#define的一些常见面试题。
1、What is the output of the following code?
#define SQR(x) (x*x)
main()
{
int a,b=3;
a=SQR(b+2);
printf("\n%d",a);
}
a=b+2*b+2=3+2*3+2=11
如果用#define SQR(x) ((x)*(x)) 则输出为25
2、用预处理指令#define 声明一个常数,用以表明1年中有多少秒(忽略闰年问题)
#define SECONDS_PER_YEAR (60 * 60 * 24 * 365)UL
面试官在这里想看到这样几件事情:
1) #define 语法的基本知识(例如:不能以分号结束,括号的使用,等等)
2)懂得预处理器将为你计算常数表达式的值,因此,直接写出你是如何计算一年中有多少秒而不是计算出实际的值,是更清晰而没有代价的。
3) 意识到这个表达式将使一个16位机的整型数溢出-因此要用到长整型符号L,告诉编译器这个常数是的长整型数。
4) 如果你在你的表达式中用到UL(表示无符号长整型),那么你有了一个好的起点。记住,第一印象很重要。
3、写一个"标准"宏MIN ,这个宏输入两个参数并返回较小的一个。
#define MIN(A,B) ((A) <= (B) ? (A) : (B))
这个测试是为下面的目的而设的:
1) 标识#define在宏中应用的基本知识。这是很重要的。因为在 嵌入(inline)操作符 变为标准C的一部分之前,宏是方便产生嵌入代码的唯一方法,对于嵌入式系统来说,为了能达到要求的性能,嵌入代码经常是必须的方法。
2)三重条件操作符的知识。这个操作符存在C语言中的原因是它使得编译器能产生比if-then-else更优化的代码,了解这个用法是很重要的。
3) 懂得在宏中小心地把参数用括号括起来
问题3:const的用法与好处。
const的使用小结:
1、基本声明:
const int max=100;//标准const变量声明加初始化,因为默认内部连接所以必须被初始化,其作用域为此文件,编译器经过类型检查后直接用100在编译时替换
const int max[ ]={1,2,3,4};
struct S {int a,b;};
const S s[ ]={(1,2),(3.4)}; //以上两种都是常量集合,编译器会为其分配内存,所以不能在编译期间使用其中的值,例如:int buffer[max[2]];这样的编译器会报告不能找到常量表达式
2、修饰指针
const int a;
int const a;
const int *a;
int * const a;
int const * a const;
前两个的作用是一样的,声明a是一个常整形数。(但这样写显然是不允许的,因为const定义的变量必须初始化。)第三个表明a是一个指向常整型变量的整型指针,即a是允许修改的,a指向的变量是不允许修改的。第四个与第三个相反,即a是一个指向整型变量的常整型指针,即a是不允许修改的,a指向的变量是允许修改的。第五个很显然即a与a指向的变量均不允许修改。
3、对于类型检查
int max=100;
const int *p=&max;
//可以把一个非const对象赋给一个指向const的指针,因为有时候我们不想从这个指针来修改其对象的值;
const int max=100;
int *pi=&max;//报错,不可以把一个const对象赋值给一个非const指针,因为这样可能会通过这个指针改变指向对象的值
const int max=100;
int * ptr = const_cast
//但也存在使这种操作通过的合法化写法,使用类型强制转换可以通过指针改变const对象,但试验说明即使这种写法通过,max的值也无法通过*ptr修改
4、对于字符数组
如char * name = “china”; 这样的语句,在编译时是能够通过的,但是”china”是常量字符数组,任何想修改他的操作也能通过编译但会引起运行时错误,如果我们想修改字符数组的话就要使用char name[ ] = “china”; 这种形式。
5、修饰函数参数
const修饰函数参数是它最广泛的一种用途,它表示函数体中不能修改参数的值(包括参数本身的值或者参数其中包含的值)。
void function(const int Var); //传递过来的参数在函数内不可以改变(无意义,因为Var本身就是形参,即使在函数体内改变了Var,原Var的值也不变)
void function(const int* Var); //参数指针所指内容为常量不可变
void function(int* const Var); //参数指针本身为常量不可变(也无意义, 因为char* Var也是形参) ,因为Var此时表示为地址值,此时*Var为实参,Var为形参,在函数体内这样依旧可以修改*Var的值,但Var的地址值不变,只是此地址指向的值变了
参数为引用,为了增加效率同时防止修改。
修饰引用参数时:
void function(const Class& Var);//引用参数在函数内不可以改变
void function(const TYPE& Var); //引用参数在函数内为常量不可变
6、修饰函数返回值
const修饰函数返回值其实用的并不是很多,它的含义和const修饰普通变量以及指针的含义基本相同。
(1) const int fun1() 这个其实无意义,因为参数返回本身就是赋值。
(2) const int * fun2()
调用时 const int *pValue = fun2();
我们可以把fun2()看作成一个变量,那么就是我们上面所说的1.(1)的写法,即指针内容不可变。
(3) int* const fun3()
调用时 int * const pValue = fun2();
我们可以把fun2()看作成一个变量,那么就是我们上面所说的1.(2)的写法,即指针本身不可变。
7、修饰类对象/对象指针/对象引用
const修饰类对象表示该对象为常量对象,其中的任何成员都不能被修改。对于对象指针和对象引用也是一样。
const修饰的对象,该对象的任何非const成员函数都不能被调用,因为任何非const成员函数会有修改成员变量的企图。
例如:
class AAA
{
void func1();
void func2() const;
}
const AAA aObj;
aObj.func1(); ×
aObj.func2(); 正确
const AAA* aObj = new AAA();
aObj->func1(); ×
aObj->func2(); 正确
8、修饰类的成员变量
const修饰类的成员函数,则该成员函数不能修改类中任何非const成员函数。一般写在函数的最后来修饰。
class A
{
…
void function()const; //常成员函数, 它不改变对象的成员变量. 也不能调用类中任何非const成员函数。
}
对于const类对象/指针/引用,只能调用类的const成员函数,因此,const修饰成员函数的最重要作用就是限制对于const对象的使用。
使用const的好处:
1) 关键字const的作用是为给读你代码的人传达非常有用的信息,实际上,声明一个参数为常量是为了告诉了用户这个参数的应用目的。如果你曾花很多时间清理其它人留下的垃圾,你就会很快学会感谢这点多余的信息。(当然,懂得用const的程序员很少会留下的垃圾让别人来清理的。)
2) 通过给优化器一些附加的信息,使用关键字const也许能产生更紧凑的代码。
3) 合理地使用关键字const可以使编译器很自然地保护那些不希望被改变的参数,防止其被无意的代码修改。简而言之,这样可以减少bug的出现。
问题4:C与C++中const的不同。
常量的引进是在早期的C++版本中,当时标准C规范正在制订。那时,常量被看做一个好的思想而被包含在C中。但是,C中的const的意思是“一个不能被改变的普通变量”。在C中,它总是占用内存,而且它的名字是全局符。C编译器不能把const看成一个编译期间的常量。在C中,如果写:
const bufsize=100;
char buf[bufsize];
尽管好像做了一件合理的事,但这将得到一个错误的结果。因为bufsize占用内存某个地方,所以C编译器不知道它在编译时的值。在C语言中可以选择这样书写:
const bufsize;
这样写在C++中是不对的,而C编译器则把它作为一个声明,这个声明知名在别的地方有内存分配。因为C默认const是外部连接的,C++默认const是内部连接的,这样,如果在C++中想完成在C中同样的事情,必须用extern把内部连接改成外部连接:
extern const bufsize;
这种方法也可用在C语言中。在C语言中使用限定符const不是很有用,即使是在常数表达式里(必须编译期间被求出)想使用一个已命名的值,使用const也不是很有用的。C迫使程序员在预处理器里使用#define。