知识点整理:用const声明的变量和#define定义的宏
严格地说两者定义的都不是常量,只是被用来表示常量。
1. #define是预处理器指令(宏定义),在编译前就会把所有#define定义的宏名全部按原样替换为其定义的值。
使用#define 需要注意三个问题,一是#define具有边缘效应,举例如下:
#include <stdio.h>
#define LENGTH 10+10
//正确写法 #define LENGTH (10+10)
#define WIDTH 5
#define NEWLINE '\n'
int main(){
int area;
area = LENGTH * WIDTH;
printf("value of area : %d", area);
printf("%c", NEWLINE);
return 0;
}
(代码出自http://www.runoob.com/cprogramming/c-constants.html的评论区)
结果是60。
如果希望结果是100的话需要写成:
#define LENGTH (10+10)
所以如果使用#define定义了表达式,需要将每个变量都加上括号,并将表达式加上括号。
二是如果宏定义会产生一些预期不到的效果,例如表示中的变量出现了多次,则对变量使用++和--操作符再应用表达式时,++和--的效果会累计:
#define max(a,b) ((a) > (b) ? (a) : (b))
...
int a = 5, b = 0;
max(++a, b); // a 的值增加了2次, a的值为7,因为第一次++a导致a的值为6,满足三目运算符的条件,因此执行“:”前的部分,但由于预处理时替换为++a因此a又增加了一次为7
max(++a, b+10); // a 的值只增加了1次, a的值为6,因为第一次++a导致a的值为6,但b在预处理时替换为b+10为10,不满足三目运算符的条件,因此执行“:”后的部分,a不再增加
所以一般使用inline修饰的内联函数和模板实现相同的功能:
template<class T> inline const T& max(const T& a, const T& b) { return a > b ? a : b; }
---------------------
(代码片段出自https://blog.csdn.net/wangjun_huster/article/details/69815606)
三是用#define 定义的宏名不会出现在编译器的报错信息中。例如:
#define ASPECT_RATIO 1.653
编译器会永远也看不到ASPECT_RATIO这个符号名,因为在源码进入编译器之前,它会被预处理程序去掉,于是ASPECT_RATIO不会加入到符号列表中。
如果涉及到这个常量的代码在编译时报错,就会很令人费解,因为报错信息指的是1.653,而不是ASPECT_RATIO。
如果ASPECT_RATIO不是在你自己写的头文件中定义的,你就会奇怪1.653是从哪里来的,甚至会花时间跟踪下去。
这个问题也会出现在符号调试器中,因为同样地,你所写的符号名不会出现在符号列表中。
---------------------
(代码片段出自https://blog.csdn.net/wangjun_huster/article/details/69815606)
所以在新的标准中提倡尽量用编译器而不用预处理,即尽量使用const而不使用#define。
使用#define的好处:
#define定义的常量可以在预处理器中使用:你可以将其和#ifdef一起使用,在它的值的基础上做条件编译,或者使用连接符#以获取一个值对应的字符串。并且因为编译器在编译时知道它的值,编译器将可以在该值的基础上进行优化。
2. const 定义的是变量不是常量,只是这个变量的值不允许改变是常变量!带有类型,编译运行的时候存在类型检查。const定义的常量等同于只读变量,值在链接时才会知道。
const的不足是定义的常量对于编译器不是100%的常量,数组长度不能是const常量(因为编译的时候不能知道数组的确定大小),只能是#define定义的常量。条件编译的时候也只能使用#define定义的常量。
const只是个限定符,表示一个变量不能在运行时间被修改。但其他所有属于变量的特性仍保留着:它有已分配的内存(原文是allocated storage),而且这个内存可能有地址。所以代码不将它(const变量)看作常量,而通过访问指定的内存位置指代该变量(除非是static const,这样它就会被优化),然后再运行时间加载它的值。然后因为const变量有已分配的存储器,如果你将它加入一个头文件然后在多个C源代码文件中包含它,你会得到一个“符号重定义”的链接错误,除非你将它标记为extern。而且在这种情况下,编译器不能针对其真实值优化代码(除非打开全局优化)。
const的优点:
(1) const 可以节省空间,避免不必要的内存分配。 例如:
#define NUM 3.14159 //常量宏
const doulbe Num = 3.14159; //此时并未将Pi放入ROM中 ......
double i = Num; //此时为Pi分配内存,以后不再分配!
double I= NUM; //编译期间进行宏替换,分配内存
double j = Num; //没有内存分配
double J = NUM; //再进行宏替换,又一次分配内存!
const 定义常量从汇编的角度来看,只是给出了对应的内存地址,而不是象 #define 一样给出的是立即数,所以,const 定义的常量在程序运行过程中只有一份拷贝(因为是全局的只读变量,存在静态区),而 #define 定义的常量在内存中有若干个拷贝。
(2) 提高了效率。 编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高。
---------------------
(引用出自http://www.runoob.com/note/26527,作者sanshi)
3. 两者的区别总结:
(1) 编译器处理方式不同
- #define 宏是在预处理阶段展开。
- const 常量是编译运行阶段使用。
(2) 类型和安全检查不同
- #define 宏没有类型,不做任何类型检查,仅仅是展开。
- const 常量有具体的类型,在编译阶段会执行类型检查。
(3) 存储方式不同
- #define宏仅仅是展开,有多少地方使用,就展开多少次,不会分配内存。(宏定义不分配内存,变量定义分配内存。)
- const常量会在内存中分配(可以是堆中也可以是栈中)。
---------------------
(引用出自http://www.runoob.com/note/26527,作者sanshi)
参考文章:
原文:http://www.runoob.com/cprogramming/c-constants.html
来源:runoob
原文:http://www.runoob.com/note/26527
作者:sanshi
来源:runoob
原文:https://blog.csdn.net/wangjun_huster/article/details/69815606
作者:wangjun_huster
来源:CSDN
原文:https://www.cnblogs.com/collectionne/p/6713651.html
作者:collectionne
来源:博客园