
题主问到了学习C语言的一个麻烦之处:既要打破砂锅问到底,又不能死钻牛角尖。
C语言从理论到实际,有三个完全独立的层次:
1、C语言标准所定义的行为。
2、C编译器编译出的结果。
3、C运行时表现出的实际行为。
想一想,在可能性空间有三个集合互不为子集,可能把空间分割成几个区域?
这个图画的可能很不严谨。它所代表的意思简单来说是这样:
1、一般情况下,设计良好的C语言代码能够让编译器编译出预期的机器指令,并且在目标机器上被正确执行。
2、C标准未明确定义的行为,可能会被编译器以合理的方式处理,也可能不会。无论报错、不处理、正确处理都认为是合理的。
3、C编译器编译出的机器码,实际执行结果与运行环境有关。例如不同版本的C runtime库,行为略有区别。或是是两个指令集兼容的CPU,因为内存设置不同、权限不同、电路板不同,而得出有差异的结果。
所以在学习中遇到奇怪的情况时,要分析——这个情况是必然出现的,还是与当前执行环境相关的。比如很多野指针、变量未初始化引起的现象,就属于偶然现象。
以题主的问题为例,理解这个问题的关键是:
const语法,到底在保护什么?
理解1:const仅代表不能通过变量名a去修改那个数字。即 a = 2 就会报错,但不保护绕过变量a去修改a的值的情况。
理解2:const所保护的是变量a所占用的存储空间(堆上、栈上或其它空间),任何试图修改这块空间中的数字1的行为,都会报错。
第1种理解属于弱保护,第2种理解属于强保护。
但问题是:要想实现保护,需要编译器、运行时环境的协同配合。
所以,编译器承诺提供哪种保护,运行时到底能否做到所承诺的保护,都不是完全确定的。
比如某些单片机,会把a的地址放到硬件的只读区域,直接烧写进ROM,从而实现强保护;而一般情况下可以通过指针强制转换等方式,绕过const保护修改掉a的值。
