本来以为 const 修饰变量就是不可已修改的,但是看了一个关于c语言的视频发现,原来是发现可以修改的,可是自己去实践的时候发现其实没有那么简单。
类型1:
int main(int argc, const char * argv[]) {
const int a = 10;
int *p = (int *)&a;
printf("%p---%p---%p \n", &a, p, &p);
*p = 20;
printf("%p---%p---%p \n", &a, p, &p);
printf("%d--%d \n", a, *p);
// 0x7ffeefbff5fc---0x7ffeefbff5fc---0x7ffeefbff5f0
// 0x7ffeefbff5fc---0x7ffeefbff5fc---0x7ffeefbff5f0
// 10--20
return 0;
}
类型2:
int main(int argc, const char * argv[]) {
volatile const int a = 10;
int *p = (int *)&a;
printf("%p---%p---%p \n", &a, p, &p);
*p = 20;
printf("%p---%p---%p \n", &a, p, &p);
printf("%d--%d \n", a, *p);
// 0x7ffeefbff5fc---0x7ffeefbff5fc---0x7ffeefbff5f0
// 0x7ffeefbff5fc---0x7ffeefbff5fc---0x7ffeefbff5f0
// 20--20
return 0;
}
类型3:
const int a = 10;
int main(int argc, const char * argv[]) {
int *p = (int *)&a;
printf("%p---%p---%p \n", &a, p, &p);
*p = 20;
printf("%p---%p---%p \n", &a, p, &p);
printf("%d--%d \n", a, *p);
// 0x100001fac---0x100001fac---0x7ffeefbff5f8
// Thread 1: EXC_BAD_ACCESS (code=2, address=0x100001fac)
return 0;
}
总结:
通过以上三种情况分析,
- const局部变量存储在堆栈中,可通过指针修改其值;
- const变量在预处理时处理,编译器只对其值读取一次。 所以 例子1中 a输出保持不变,但是例子2中 a 已经被修改
- const全局变量存储在全局存储空间,其值只有可读属性,所以例子3中修改会导致崩溃
以上例子在Xcode中实现,不同编译器可能结果不同,因为这都是有编译器的优化导致的。
这里涉及到一个叫常量折叠的概念(常量折叠就是将常量表达式计算求值,并用求得的值来替换表达式,放入常量表。可以算作一种编译优化。(预编译阶段)), 即编译器虽然会给a分配空间(如果取a的地址进行操作的时候,会强迫编译器进行内存分配), 但是在预编译阶段, 会把所有的a用10替换(这就有点像#define了), 所以虽然&a地址存放的内容改变了, 但是a依然为10.
网友评论