const在C与C++中的区别

  在C中,const不是常量,只能说是一个不能改变的变量(注意是变量),C编译器不能把const看成看成一个编译期间的常量,因为他在内存中有分配,C编译器不知道他在编译期间的值。所以不能作为数组定义时的下标,因为它必须为常量。

  在C中,const int a;是可以的,因为这只是声明一个变量,告诉编译器,我这里是声明,指明在别的地方有内存分配。但在C++中这样写是不正确的,C++中const默认是内部链接,C中默认是外部链接,为了起到和c语言一样的效果,C++需要将const修饰为extern,因为extern优先级高于const,所以变量会被变为extern外部链接,起到和C语言一样的效果。[ (1) 内连接:编译器只对正被编译的文件创建存储空间,别的文件可以使用相同的表示符或全局变量.C/C++中内连接使用static关键字指定.(2) 外连接:所有被编译过的文件创建一片单独存储空间.一旦空间被创建,连接器必须解决对这片存储空间的引用.全局变量和函数使用外部连接.通过extern关键字声明,可以从其他文件访问相应的变量和函数. ] 通俗的讲:在c++ 中const 对象默认为文件的局部变量。与其他变量不同,除非特别说明,在全局作用域声明的 const 变量是定义该对象的文件的局部变量。此变量只存在于那个文件中,不能被其他文件访问。通过指定 const 变更为 extern,就可以在整个程序中访问 const 对象。

  C++中是否为const分配内存空间要看具体情况,如果被声明为extern或者取const变量地址,就需要为const变量分配空间。

  当在自己的文件中使用const的时候,C++不会为const常量分配空间,因为这是一种优化措施,没有必要浪费空间去存储一个常量,此时const int a=5 就相当于#define a 5,当在其他文件使用的时,需要分配内存,同样在程序内部引用的时候,也需要分配内存,因为这两者都是采用寻址的技术去使用的,不分配内存就没有地址。C++中定义常量的时候不再采用define,因为define只做简单的宏替换,并不提供类型检查。

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

 1 int main()
 2 {
 3     const int a = 2;
 4     int* p = (int*)(&a);
 5     *p = 30;
 6     cout << &a << endl;
 7     cout << p << endl;
 8     cout << a << endl;
 9     cout << *p << endl;
10     return 0;
11 }
12  
13 /*运行结果:
14 -----------
15 010FF958
16 010FF958
17 2
18 30
19 -----------
20 */

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

  但是在C语言中却不是这样,C没有constant folding的概念,用const定义一个常量的时候,编译器会直接开辟一个内存空间存放该常量。不会进行优化。同样的例子在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 }
12  
13 /*运行结果
14 ------------
15 61fe14
16 61fe14
17 30
18 30
19 ------------*/

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

  以上的例子针对局部的const常量而言,对全局的const变量,C++仍旧采用constant folding策略,故以下代码是行得通的:
1 const int a = 3;
2 int arr[a];

  但C会报错: error: variably modified 'arr' at file scope, 原因在于GCC认为a只是一个普通的全局变量,而变量是不能用来指定数组的长度的,这是针对全局数组而言。但如果是局部的数组的话,就算是int a = 3; int arr[a];这种都是可以的,若在C和C++中如果我们仍然用int *p = (int*)(&a);这种方法来修改它内存中的值,编译时不会报错,但是运行时会报错误,因为a是放在只读的全局数据区中,修改该区中的数据会引发段错误。

猜你喜欢

转载自www.cnblogs.com/WindSun/p/10207934.html