知识点整理:用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

来源:博客园 

 

posted @ 2018-10-24 15:25  天南星2018  阅读(723)  评论(0编辑  收藏  举报