偶然的因素,对const来了点兴趣,做了一下实验:
1. 语法:const、指针
在gcc中, 对于C语言,下面的语句是合法的:
const int a=0;
int *p=&a;
而C++中,需要手工强制转换才能编译通过:
const int a=0;
int *p=(int *)&a;
2. 既然能够将const变量的地址赋给指向非const变量的指针,那么能否改变通过指针改变const变量的值呢?
1)在gcc中,编译执行以下代码:
const int c=2;
int *p=&c;
*p=1;
printf("c is :%d/n",c);
编译时会有警告:警告:初始化丢弃了指针目标类型的限定
结果为:
c is 1
说明虽然有警告,但是顺利编译通过,并且成功改变了常量c的值(从2变为1)。
2.接下来看下面一段代码:
#include <stdio.h>
#include <unistd.h>
int main(void)
{
const int c=2;
int a=0;
const int *p;
p=&a;
int *p2=&a;
p2[1]=-1;
printf("p2[1] is :%d/n",p2[1]);
printf("a is :%d/n",a);
printf("c is :%d/n",c);
printf("c address is:%d/n",&c);
printf("p2[1] address is:%d/n",p2+1);
printf("*(&c) is :%d/n",*(&c));
}
这段代码,程序会有怎样的输出呢?
1.保存为后缀为.c的文件,用gcc编译,执行结果如下:
p2[1] is :-1
a is :0
c is :-1
c address is:-1076230280
p2[1] address is:-1076230280
*(&c) is :-1
说明p2+1的地址和c的地址一样,程序成功的间接改变了c的值(p2越界访问,不容易看出)
考虑一下这段代码在C++中会有怎样的表现呢?
保存后.cpp的文件,用g++编译,执行结果如下:
c is :2
p2[1] is :-1
a is :0
c is :2
c address is:-1077876024
p2[1] address is:-1077876024
*(&c) is :2
这个就奇怪了……
明明p2[1]的地址和c的地址一样,为什么p2[1]的值和c不一样呢?
后来想到因为c是常量,编译器可能优化,将c放入寄存器,取值的时候取的是寄存器的值,内存里面的值实际已经被改变了。
为了证实这个想法,我们将c的定义改为:
volatile const int c=2;
再次用g++编译,执行结果如下:
p2[1] is :-1
a is :0
c is :-1
c address is:-1074816520
p2[1] address is:-1074816520
*(&c) is :-1
结果证实了我的猜测,c在内存里面的值确实改变了。(注:如果不把c改为volatile,即使将g++设置为-O0,程序输出的c依然是2,囧……)
以上纯粹是无聊所作,没啥大的意义。不过,从这里我也能稍微理解一下那些说“指针不安全”的人了……上面例子中的p2越界竟然改变了const变量。看来const也不一定const啊……同时,g++默认对程序做的优化……这个如果没想到它有可能变量放到寄存器的话,估计对上面默认编译执行的结果会疑惑不已了……囧。