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

时间:2022-07-15 06:50:43

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

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

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

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

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

结果:

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

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

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

 int main()
{
const int a = ;
int* p = (int*)(&a);
*p = ;
printf("%x\n",&a);
printf("%x\n",p);
printf("%i\n",a);
printf("%i\n",*p);
return ;
}

结果:

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

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

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

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

//global variable
const int a = ;
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变量,不管是全局的还是局部,都是放在只读数据区,所以无法用前面的方法来修改内存空间里面的值,编译时就会报错。