符号常量:
1.用#define定义的宏常量 进入编译阶段前就被替换成多代表的字面常量,所以本质是字面常量
2.用const定义的常量
C语言中,const定义的是不能让你个修改的量,会给它分配存储空间(外链接)
C++中,基本数据类型的常量,编译器放在符号表中,不分配存储空间,ADT/UDT的const对象则需要分配存储空间。默认内链接
特殊情况:强制声明为extern的符号常量或取符号常量的地址也会分配存储空间以满足用户的需求。
好玩的代码
1 #include<iostream>
2 using namespace std;
3 class A{
4
5 public:
6 A():n(100){}
7 int n;
8 };
9 int main()
10 {
11 const int a=1;
12 cout<<a<<endl;
13 int* p=(int*)&a;//取常量的地址
14 *p=2;// 迂回修改
15 cout<<*p<<endl;//2,修改的是拷贝内容
16 cout<<a<<endl;//1,原始常量没有变化
17
18
19 const A m;
20 A* pa=(A*)&m;//去除常数属性
21 pa->n=1000;
22 cout<<m.n<<endl;//1000,修改const对象成功
23 cout<<pa->n<<endl;//1000,“迂回修改成功”
24
25 }
基本常量在符号表中,编译器会重新在内存中创建一个拷贝,你通过其地址访问的就是这个拷贝的常量,而不是原始常量
对于构造类型的const 常量,实际它是编译时不允许修改的常量,因此你可以绕过编译器的静态安全检查机制,在运行是改变它的值。
外链接:C语言默认是外链接,分配存储,你不可在两个或以上的编译单元中同时定义一个符号常量(重复定义错误)
内链接:C++默认,可以定义在头文件中,编译器会认为他们是不同的符号常量,因此每个编译单元会在独立编译是为他们分配存储空间,然后在链接是合并。
契约性常量
契约性const对象的定义未使用const关键字,但可以被看作一个const对象
void print(const int& n)
{
cout<<n<<endl;
}
int main()
{
int n=1;
print(n);
}
枚举常量
C++/C的构造类型enum实际上用来定义一些相关常量的集合,标准C++/C规定枚举常量可以扩展,并非受限一般整数范围。
enum Gigantic
{
SMALL=0;
GIGANTIC=10000000000
}
几点建议:
尽量使用含义直观的符号常量来表示那些将在程序中多次出现的数字或字符串
C++中将需要对外公开的常量放在头文件中,不许要公开的常量放在定义文件的头部,为便于管理,可以把不同模块的常量集中存放在一个共用的头文件中。
某一常量与其他常量密切相关,应该在定义中包含这种关系,不应给出一些孤立的值
const float RADIUS-100; const DIAMETER=2*RADIUS;
尽量使用const避免define带来的边际效应,纯字符替换
我的发现:
1 #include<stdio.h>
2 int main()
3 {
4 const int a=123;
5 printf("%d\n",a);
6 int* p=(int*)&a;
7 *p=456;
8 printf("%d\n",a);
9
10
11 }
上面这段C代码:
C++编译器编译结果: 123,123 编译器进行优化,后面的n一律用n代替,改成volatile const int a=123, 则不会优化,每次输出从n的内存读取
C编译器编译结果:123,456 不会进行优化。