您的位置:首页 > 编程语言 > C语言/C++

c和c++关于const的一些区别

2015-06-07 10:35 429 查看
转自:http://www.cnblogs.com/ylan2009/p/4151744.html

以下参考了网上的一些资料并通过程序验证。

注意,以下情况都是用gcc和g++编译器得到的结果,用vs编译器又会有所不同。

以下说下c和c++中const定义的常量的一些区别:

c++中用const定义了一个常量后,不会分配一个空间给它,而是将其写入符号表(symbol table),这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高。但是const定义的常量本质上也是一个变量,是变量就会有地址,那么什么时候会分配内存?看看下面的代码:

int main(){
const int a  = 2;
int* p = (int*)(&a);
*p = 30;
cout<<&a<<endl;
cout<<p<<endl;
cout<<a<<endl;
cout<<*p<<endl;
}


结果:



我们看到,通过 int*p = (int*)(&a);这种方法,可以直接修改const常量对应的内存空间中的值,但是这种修改不会影响到常量本身的值,因为用到a的时候,编译器根本不会去进行内存空间的读取。这就是c++的常量折叠(constant folding),即将const常量放在符号表中,而并不给其分配内存。编译器直接进行替换优化。除非需要用到a的存储空间的时候,编译器迫不得已才会分配一个空间给a,但之后a的值仍旧从符号表中读取,不管a的存储空间中的值如何变化,都不会对常量a产生影响。

但是在c中却不是这样.c没有constant folding的概念,用constant定义一个常量的时候,编译器会直接开辟一个内存空间存放该常量。不会进行优化。同样的例子在c下面会产生不同的结果:

1 int main()
2 {
3     const int a  = 2;
4     int* p = (int*)(&a);
5     *p = 30;
6     printf("%x\n",&a);
7     printf("%x\n",p);
8     printf("%i\n",a);
9     printf("%i\n",*p);
10     return 0;
11 }


结果:



我们看到,在c里面,一个被const定义为常量的值,堂而皇之地被修改了,而且编译器没有报任何错误 !

如果我们进一步深入可以发现,对于以上两个例子来说,a都是定义在某个函数之内的(比如main()函数),不管是c还是c++,本质上都只是将其当成一个普通的局部变量来对待,都只是在栈上分配空间。所以const根本就不能起到阻止修改其内存空间的作用,一个合法的强制类型转换就可以轻松搞定。c++比c好的地方就在于使用了constant folding的机制,使得常量的值跟对应的内存空间无关,从而保护了该常量值。

以上的例子是针对局部的const常量而言,对全局的const变量,c++仍旧采用constant folding策略,故以下代码是行得通的:

//global variable
const int a = 3;
int arr[a];


但是c会报错: error: variably modified 'arr' at file scope, 原因在于gcc认为a只是一个普通的全局变量,而变量是不能用来指定数组的长度的。当然,这是针对全局数组而言,如果是局部的数组的话,就算是int a = 3; int arr[a];这种都是可以的,因为c里面还有一种叫变长数组的东西(我晕~,貌似因为两者的实现机制不一样,这个要再看看)

另外,对于a,在c和c++中如果我们仍然用int *p = (int*)(&a);这种方法来修改它内存中的值,编译时不会报错,但是运行时会报段错误,因为a是放在只读的全局数据区中,修改该区中的数据会引发段错误。

在vs编译器下:

1.不支持变长数组,一个变量除非被声明为const,否则不能用来声明数组的长度。

2.const变量,不管是全局的还是局部,都是放在只读数据区,所以无法用前面的方法来修改内存空间里面的值,编译时就会报错。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: