Posts Tagged ‘符号表’

9
Dec

编译器如何处理基本类型的const常量

by huubby in C and CPP

前段时间看《高质量C++&C编程指南》,看到一段比较有意思的代码,见下面这一坨:

const long        lng = 100;

long * pLng = (long *)&lng;

*pLng = 20;

cout<<*pLng<<endl;

cout<<lng<<endl;

乍一看,嗯,确实有点问题,第二句long * pLng = (long *)&lng;消除了lng的常量性,这样指针就可以绕过编译器的检查而直接修改const常量的值。我自信满满的认为,输出结果肯定是20,20。继续往下看,这本破书竟然告诉我,输出的是20,100。当时我就“震精”了,立刻怀疑自己买的是某小印刷厂出的盗版书,又或者林锐这家伙脑子进水,乱写瞎忽悠。

我是个不信邪的人,马上拿小抄抄下来,第二天到电脑上一跑,输出的竟然真的是20,100。好消息是,我买的不是盗版书,大牛林锐也没脑子进水,乱写瞎忽悠。那就继续翻书找答案,原来人林锐早说了,“编译器把基本类型的const常量放入符号表中”。取该基本类型常量的地址,如long * pLng = (long *)&lng;时,编译器在内存中创建了一个该值的内存拷贝,然后把这个拷贝的地址返回给了pLng指针,以后修改指针指向的值时,修改的就是内存中拷贝的值,而不是原始的基本类型常量。代码加上注释后如下:

const long        lng = 100;       //基本类型常量,放入符号表中

long * pLng = (long *)&lng;     //在内存中创建一个拷贝,并且返回该拷贝的地址给pLng

*pLng = 20;                      //修改的是内存中的拷贝的值

cout<<*pLng<<endl;        //输出修改后的拷贝的值

cout<<lng<<endl;           //符号表的值

下面还有坨代码:

class _MyClass

{

public:

_MyClass(int var):m_var(var){}

public:

int                       m_var;

};

const _MyClass        myCls(23);

_MyClass*          pMyCls = (_MyClass*)&myCls;

pMyCls->m_var = 45;

cout<<myCls.m_var<<endl;

cout<<pMyCls->m_var<<endl;

这个时候,输出的就是45,45啦。用户自定义类型的常量会分配内存空间,而不是放入符号表。

请注意:编译器只是将基本类型的const常量放入符号表中,其他用户自定义类型,非基本类型const常量,编译器会为其分配内存空间,而在编译时进行只读性检查。

2009年12月8日星期二