常量数据在程序执行前就已经存在,他们被编译到可执行文件中,也就是当程序自动运行时,他们便会被加载出来,然后这些数据就会在常量数据区保存,该区域的属性中是没有写的权限的.常量数据的地址减去基地址便是他在文件中的偏移地址.
在c++中可以用宏机制表示常量,也可以用const将变量定义成一个常量.
Define:
Define 是一个真实常量,在编译时就将宏名称替代成相应的信息.
#include <iostream>
#define n 100;
using namespace std;
int main()
{
int a,b,c,d,e;
a = n;
b = n;
c = n;
d = n;
e = n;
//debug环境下对应汇编代码
//0x004016be <+14>: mov DWORD PTR [esp+0x1c],0x64
//0x004016c6 <+22>: mov DWORD PTR [esp+0x18],0x64
//0x004016ce <+30>: mov DWORD PTR [esp+0x14],0x64
//0x004016d6 <+38>: mov DWORD PTR [esp+0x10],0x64
//0x004016de <+46>: mov DWORD PTR [esp+0xc],0x64
return 0;
}
优点:
一 避免了模糊数字出现,增加了可读性.
二 可以很方便的修改和调整
三 提高了程序的执行效率。(与变量赋值相比,减少了读写内存的操作)
缺点:
预处理指令只是简单的值替代,缺乏类型的检测机制,这样预处理不能享受到c++严格的类型检查机制,从而引发一系列的错误隐患。正式这个原因,从而引入了const,const的初始目的,正式为了取代编译指令,消除它的缺点继承他的优点。
Const:
Const是一个假常量,它是由编译器判断实现的常量,本质还是一个变量,只是在编译的时候进行了是否对其值更改的检查,完全可以通过指针间接访问它而改变其值。
#include <iostream>
using namespace std;
int main()
{
const int a = 23;
//00E15398 mov dword ptr[a], 17h
int b;
int *p = (int*)&a;
//00E1539F lea eax, [a]
//00E153A2 mov dword ptr[p], eax
*p = 40;
//00E153A5 mov eax, dword ptr[p]
//00E153A8 mov dword ptr[eax], 28h
b = a;
//00E153AE mov dword ptr[b], 17h
cout << a << b << *p << endl;
return 0;
}
<span style="font-family:宋体;">//结果 232340</span>
当a初始值为常量时,编译器在编译的过程中将用到a的地方都被23(17h)替代,但是a本质还是一个变量,所以可以瞒过编译器空过指针的方式对其修改。
#include <iostream>
using namespace std;
int main()
{
int c = 23;
//00F25398 mov dword ptr[c], 17h
const int a = c;
//00F2539F mov eax, dword ptr[c]
//00F253A2 mov dword ptr[a], eax
int b;
int *p = (int*)&a;
//00F253A5 lea eax, [a]
//00F253A8 mov dword ptr[p], eax
*p = 40;
//00F253AB mov eax, dword ptr[p]
//00F253AE mov dword ptr[eax], 28h
b = a;
//00F253B4 mov eax, dword ptr[a]
//00F253B7 mov dword ptr[b], eax
cout << a << b << *p << endl;
return 0;
}
<span style="font-family:宋体;">//结果 404040</span>
当a的初始值为变量时,编译器并没有为其替代,所以通过p指针修改了a的值,使其不再是23而是40.
优点:
一 cosnt定义常量本质就是一个变量,所以它享受了c++的严格的类型检查,使得使用比define要安全的多。
二 由于定义时必须初始化,所以避免个意义模糊现象,同样也方便的修改和调整
三 可以节省空间 ,避免不必要的内存分配
四 当右值为常量时,编译器会在编译过程中将其进行和define一样的替代,省略了对const变量的读写内存的操作使得效率也会提高.
缺点: 当右值 为变量时,编译器并没有为其替代,所以效率比define 会弱。
拷贝与const:
顶层const不受影响,底层const 拷入与拷出对象必须有相同的const,或者两个对象数据类型必须能够转化。