本帖最后由 lishutong 于 2017-12-9 22:42 编辑
在学习C语言时,无数本教材都告诉我们:用const 类型 标志符; 这种方式是定义一个常量,也就意味着不可以修改。但真的只是这样吗?例如: int main () {
const int var = 0x1;
var = 2;
printf("%d\n", var);
return 0;
}
你可能会说: var是不可修改的。从表面上看,似乎是这样,现在来编译一下,编译器提示以下的错误。 app.c(4): error: #137: expression must be a modifiable lvalue
编译器提示var必须是可以修改(modifiable)的量。var真的不可以修改吗? 一个可以修改的const原因现在,我们对代码进行一下修改。通过这个修改你可以发现const声明的常量是可以修改的。请看代码: <pre class="highlight" style="box-sizing: border-box; overflow: auto; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 13px; padding: 9.5px; margin-bottom: 10px; line-height: 1.42857143; color: rgb(51, 51, 51); word-break: break-all; background-color: rgb(245, 245, 245); border: 1px solid rgb(204, 204, 204); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px;"><code style="box-sizing: border-box; font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: inherit; color: inherit; background-color: transparent; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; white-space: pre-wrap;">int main () {
const int var = 0x1;
int * pVar = (int *)&var;
*pVar = 0x2;
return 0;
}</code></pre>
这段代码,如果我们把它放在Keil + STM32平台上跑,并且将var和pVar加入变量watch窗口中,会发现下面的效果: 我们惊奇地发现:用const声明的var值,可以通过指针pVar间接修改!。为什么会这样? const常量可以修改的原因分析上面的代码可以发现,原因非常简单: 在Keil + STM32平台上,用const声明的var实际上是在堆栈空间中分配的,也就是说,从物理上来看,var是分配在内存中。而此时硬件上也没有开启任何内存检查的机制,所以,我们可以间接地通过PVar指针对这个变量进行修改。
既然如此,那用const声明还有什么用? const常量的优点可以从以下几个方面来理解const常量的优势。 可以将常量放置到Flash空间通过将const声明的常量放置到函数外部作为全局,链接器会自动将该常量分配到Flash中。这样可以节省内存开销。 观察上图可以发现,var被分配在了地址0x080000388,而此空间正好在Flash区域。 现在的编译器够智能,看到了const就知道我们不想对该变量进行任何修改,自动分配到不可随意写的Flash中。既有效地保护了该常量,又节省内存空间,一举两得。 语法检查机制对我们想要只读的常量加上const,可以让编译器在编译过程中,发现代码中任何试图”违反规则,企图修改”该变量的任何代码。 例如,本文最开始的编译错误。甚至于在写代码时,好的编辑器都能实时帮我们检查这种错误。 更好的可读性此外,由于加const,其他的程序员在阅读你的代码时,能够直接了当知道这个常量是不应修改的。特别是在传递一些函数的参数时,例如: void process (const char * var) { // 一些代码 }
我们不需要再加注释说明var是不是会在process中修改。其他人只需要看到这个函数声明,就知道传入的指针不会被间接使用修改所指向的变量。 总结总结以上内容,我们对const有了一个新的了解:const声明的常量并不一定是不可修改,其主要功能是注明其不应当被修改。之后编辑器、编译器、链接器可以自行根据该声明,做出相应的处理,从而实现以下的几个特性。 - 根据硬件存储布局自动安排合理的位置
- 语法检查,有效避免写代码时出错
- 更好的可读性
注:以上测试均在Keil + STM32平台上实现。在其它平台上,const常量可能确实是不可修改的。本文的结果也指出, const常量并不一定不可修改。
原创**:欢迎关注微信公众号 01ketang http://01ketang.cc
|