博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
高质量程序设计指南c++/c语言(20)--符号常量
阅读量:4708 次
发布时间:2019-06-10

本文共 1859 字,大约阅读时间需要 6 分钟。

     存在两种符号常量,用#define定义的宏常量和用const定义的常量。宏常量是预编译伪指令,在本质上是字面常量。在c语言中,const符号常量默认是外连接的,因此会给它分配存储空间,也就是说你不能在两个编译单元中同时定义一个同名的const符号常量(重复定义错误),或者把一个const符号常量定义在一个头文件中而在多个编译单元中同时包含该头文件。但是在标准c++中,const符号常量默认是内连接的,因此可以定义在头文件中。当在不同的编译单元中同时包含该头文件时,编译器认为它们是不同的符号常量,因此每个编译单元独立编译时会分别为它们分配存储空间,而在连接时进行常量合并。

      在c++中,const定义的符号常量要区别对待:对于基本数据类型的常量,编译器会把它们放到符号表中而不分配存储空间,而const的类对象则需要分配存储空间。还有一些情况下是需要分配存储空间的,例如,强制声明为extern的符号常量或取符号常量的地址等操作,都将强迫编译器为这些常量分配存储空间,以满足用户的需求。

      你可以取一个const符号常量的地址:对于基本数据类型的const常量,编译器会重新在内存中创建一个它的拷贝,你通过其地址访问到的就是这个拷贝而非原始的符号常量;而对于复合数据类型的const常量,实际上它是编译时不允许修改的变量,因此,如果你能绕过编译器的静态类型安全检查机制,就可以在运行时修改其内存单元。

#include
using namespace std;class Integer{public: Integer():m_int(10){} int m_int;};int main(void){ const long lng=10; long *pl = (long *)&lng; //取常量的地址 *pl = 1000; //迂回修改 cout << *pl << endl; //1000, 修改的是拷贝内容 cout << lng << endl; //10, 符号表内的原始常量没有改变 const Integer a; Integer *p = (Integer *)&a; //除去常量属性 p->m_int = 1000; //迂回修改 cout << p->m_int << endl; //1000, 修改const对象 cout << a.m_int << endl; //1000, 迂回修改成功 return 0;}

      这个例子说明,const修饰符只是编译时(源代码层面或语言层面)强类型安全检查机制的一种手段,以帮助程序员发现无意中要修改它们的代码并进行纠正,而在运行时(二进制层面)无法阻止恶意的修改。也就是说“防君子不防小人”。

1、const与#define的比较

     前者比后者有更多的优点,const常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行静态类型安全检查,而对后者只进行字符替换,没有类型安全检查,并且在字符替换时可能产生意想不到的错误。

2、类中的常量

不能在类声明中初始化非静态const数据成员,如下面是错误的

class A{public:    const int SIZE = 100;};

非静态数据成员的初始化只能在类的构造函数的初始化列表里面

class A{public:    A(int n):SIZE(n){}    const int SIZE;};

上面的常量是对于每一个类A的对象而言的,怎样才能建立在整个类中都恒定的常量呢?使用enum或者static const

class A{public:    enum    {        SIZE1 = 100,        SIZE2 = 200    };    int array[SIZE1];};

枚举常量不会占用对象的存储空间,它们在编译时会被全部求值。枚举常量的缺点是不能表示浮点数和字符串。

class A{    static const int SIZE;};const int A::SIZE = 100;

 

转载于:https://www.cnblogs.com/zzj3/archive/2013/04/28/3049783.html

你可能感兴趣的文章
sublime text2 中Emmet常用的技巧 和快捷键
查看>>
浏览器对应用程序的根URL发出请求时所发生的情况(结合 DI)
查看>>
delete和delete[] 的区别
查看>>
[ACM] hdu 2177 取(2堆)石子游戏(威佐夫博弈)
查看>>
3.5 爬虫身份识别与实现网络爬虫技术语言
查看>>
python的dict,set,list,tuple应用详解
查看>>
centos7使用传统网卡名
查看>>
Sublime Text 2 增加python版本
查看>>
spring mvc dispatcherservlet处理request流程
查看>>
怎样加快master数据库的写操作?分表原则!将表水平划分!或者添加写数据库的集群...
查看>>
Netty源码分析第8章(高性能工具类FastThreadLocal和Recycler)---->第2节: FastThreadLocal的set方法...
查看>>
C# 程序之间传参数,Args 接收参数的处理
查看>>
Question
查看>>
Java基础 & 并发编程
查看>>
数据库调优 - 2 索引
查看>>
知识点
查看>>
29.Android之文本框输入自动提示学习
查看>>
微信二维码支付-模式一(PC端,解决中文乱码问题)
查看>>
SentOS安装redis
查看>>
其他博客
查看>>