1.什么是const?
const是限定符,用来修饰变量,使得它不可以被程序员修改值。
2.为什么需要const?
(1).作为常量的标志,#define的升级版本。
#define预定义处理,不能够确定类型。
#define会产生二义性,这一点在c陷阱与缺陷中有提到,比如#define typeA int *,定义
typeA a, b;会使b定义为int型。
(2).防止参数调用和函数返回值被意外改变,提供#define没有的功能。
(3).在类的设计中如果类的成员函数不改变类的成员数据,那么应当声明为const函数。
3.const的内存分配
const不像#define只是编译时替换,它会分配内存,也就是说,它的常量并非不可改变,只是
下面来看一组源码分析
4.常量指针或指针常量
int const *p =&a; //指针常量,不可以通过*p修改a的值
int * const p = &a; //常量指针,不可以修改p的地址
注意const在*的左右位置
5.全局常量的不可修改性
会报段错误,这里报错的原因在于:const int constant,这个全局常量内存分配在.rodata段,对于内
存分页机制来说,.rodata对应的页是只读的,当试图去修改该段内存时,会引发段错误。可以说,这
是真正能够保证不会被修改的常量。是在操作系统层面实现的。
6.c++ primier plus的作者建议尽量使用const。
const是限定符,用来修饰变量,使得它不可以被程序员修改值。
2.为什么需要const?
(1).作为常量的标志,#define的升级版本。
#define预定义处理,不能够确定类型。
#define会产生二义性,这一点在c陷阱与缺陷中有提到,比如#define typeA int *,定义
typeA a, b;会使b定义为int型。
(2).防止参数调用和函数返回值被意外改变,提供#define没有的功能。
(3).在类的设计中如果类的成员函数不改变类的成员数据,那么应当声明为const函数。
3.const的内存分配
const不像#define只是编译时替换,它会分配内存,也就是说,它的常量并非不可改变,只是
运行时在出现的地方替换为常量而已。因为const会分配内存,所以在类中不可以初始化const常量,
因为在类的对象还没有被创建时,系统找不到内存赋值,要在类中使用常量可以使用枚举或静态变量。
下面来看一组源码分析
<span style="font-size:14px;"> const int con_var1 = 3;
int * b = (int *)&con_var1;
*b = 5;
std::cout <<con_var1 << " "<<*b <<std::endl;
getchar();</span>
vc++6.0的反汇编代码<span style="font-size:14px;">004017A8 mov dword ptr [ebp-4],3
004017AF lea eax,[ebp-4]
004017B2 mov dword ptr [ebp-8],eax
004017B5 mov ecx,dword ptr [ebp-8]
004017B8 mov dword ptr [ecx],5
004017BE push offset @ILT+195(std::endl) (004010c8)
004017C3 mov edx,dword ptr [ebp-8]
004017C6 mov eax,dword ptr [edx]
004017C8 push eax //压栈参数
004017C9 push offset string " " (0046e01c)
004017CE push 3 //con_varl被替换成3
004017D0 mov ecx,offset std::cout (0047be90)
004017D5 call @ILT+250(std::basic_ostream<char,std::char_traits<char>
>::operator<<) (004010ff) //调用输出函数
004017DA push eax
004017DB call @ILT+640(std::operator<<) (00401285)
004017E0 add esp,8
004017E3 mov ecx,eax
004017E5 call @ILT+250(std::basic_ostream<char,std::char_traits<char>
>::operator<<) (004010ff)
004017EA mov ecx,eax
004017EC call @ILT+475(std::basic_ostream<char,std::char_traits<char>
>::operator<<) (004011e0)
004017F1 mov ecx,dword ptr [__iob+4 (0047788c)]
004017F7 sub ecx,1
004017FA mov dword ptr [__iob+4 (0047788c)],ecx
00401800 cmp dword ptr [__iob+4 (0047788c)],0
00401807 jl main+9Bh (0040182b)
00401809 mov edx,dword ptr [__iob (00477888)]
0040180F movsx eax,byte ptr [edx]
00401812 and eax,0FFh
00401817 mov dword ptr [ebp-0Ch],eax
0040181A mov ecx,dword ptr [__iob (00477888)]
00401820 add ecx,1
00401823 mov dword ptr [__iob (00477888)],ecx
00401829 jmp main+0ABh (0040183b)
0040182B push offset __iob (00477888)
00401830 call _filbuf (00420b10)
00401835 add esp,4
00401838 mov dword ptr [ebp-0Ch],eax
0040183B xor eax,eax
0040183D pop edi
0040183E pop esi
0040183F pop ebx
00401840 add esp,4Ch
00401843 cmp ebp,esp
00401845 call __chkesp (004209b0)
0040184A mov esp,ebp
0040184C pop ebp
0040184D ret</span>
从中可以看出,const变量在栈中分配内存,通过指针间接访问可以改变其内存,但是在输出的时候系
统是直接push 3将立即数压栈的,所以这是一个替换功能,保证了const的不可改变性。4.常量指针或指针常量
int const *p =&a; //指针常量,不可以通过*p修改a的值
int * const p = &a; //常量指针,不可以修改p的地址
注意const在*的左右位置
5.全局常量的不可修改性
<span style="font-size:14px;">#include<iostream>
using namespace std;
const int constant=1;
int main()
{
unsigned int addr;
int * pconst;
addr=(unsigned int)&constant;
pconst=(int *)addr;
cout<<&constant<<" "<<&addr<<endl;
*pconst=10;//segment fault
cout<<constant<<endl;
return 0;
} </span>
这里修改const后,会引发运行时错误。会报段错误,这里报错的原因在于:const int constant,这个全局常量内存分配在.rodata段,对于内
存分页机制来说,.rodata对应的页是只读的,当试图去修改该段内存时,会引发段错误。可以说,这
是真正能够保证不会被修改的常量。是在操作系统层面实现的。
6.c++ primier plus的作者建议尽量使用const。