分享

编程时const的那些细节!

 汉无为 2021-07-20
本文主要跟大家讲解一下C语言中const的那些事。

01

const在C和C++中

图片

首先我们来看如下程序:

1#include <stdio.h>
2#include <stdlib.h>
3
4const int constSize = 5;
5int array[constSize] ={0};
6
7int main(int argc, char *argv[]) {
8
9    printf('Hello const\n'); 
10    return 0;
11}

假如把const修饰的名称视为常量,那么其作为数组大小设置应该能够通过编译才对,而在Dev下编译得到如下结果:

图片

大体的意思是编译器认为你在修改这个数数组,也就是说constSize是一个变量,程序正在用一个变量访问一个数组,所以在C语言中const修饰的部分固定不变,但终究不是常量,而是一个只读变量。

而同样的程序在C++编译环境中是可以编译通过的,C++会编译优化认为其就是一个常量,所以可以用来初始化数组;当然如果你看到有些编译器用变量作为了数组的初始化大小,那一般都是其扩展功能,这里就不展开描述了。

02

const修饰全局与局部

图片
既然const是一个只读变量,是变量就应该会有其地址,于是我们通过指针绕个道看能不能修改其值。
首先看看const修饰全局变量:

1#include <stdio.h>
2#include <stdlib.h>
3
4const int constVar = 5;
5
6int main(int argc, char *argv[]) {
7
8    int *pVar = (int*)&constVar;
9    *pVar = 10;
10    printf('constVar = %d\n',constVar); 
11    printf('Hello const\n'); 
12    return 0;
13}

然而不好意思的是编译失败,得到如下结果:

图片

好吧,先不急着解释,看看const修饰局部变量情况又是如何的,同样修改如上代码:

1#include <stdio.h>
2#include <stdlib.h>
3
4
5int main(int argc, char *argv[]) {
6    const int constVar = 5;
7    int *pVar = (int*)&constVar;
8
9    *pVar = 10;
10    printf('constVar = %d\n',constVar); 
11    printf('Hello const\n'); 
12    return 0;
13}

编译运行,却得到了正确的结果。

图片

从上面的对比实验可以看出,通过指针修改const全局变量区域的内存会导致程序奔溃,而修改const局部变量区域的内存可以得到正确结果。
对比两者的汇编代码你会发现,这两个变量位于不同的区域。

图片

图片
全局const其分配在全局地址区域,而局部const分配在堆栈上,通过指针修改const的值是一种与编译器有关的行为,可以用指针修改堆栈上的局部变量,而全局变量const修饰以后为只读区域,一旦程序访问则会导致异常。

03

const修饰指针的老问题

图片

虽然是一个老掉牙的问题,不过小哥还是在这里顺便谈谈自己的理解,对于const修饰指针定义,最终处理的办法是:去掉所有的类型,const右侧表示什么,什么就不能被直接修改,如下所示:

1const int const * const pVar = &Var1;
2const int * const pVar       = &Var1;  
3int const * const pVar       = &Var1; 
4
5//根据规则简化: const (* const (pVar)) --> *pVar和pVar均不可修改 

以上三种方式均是等价的,啥也不能被修改,地址和数据都为只读,不管你在程序中采用*pVar作为左值还是pVar作为左值,编译器均会报错。

一旦你去掉其中一个const即可释放一种访问权限,比如:

1int * const pVar  = &Var1;  //可以访问*pVar,而修改pVar便会报错 
2const int  *pVar  = &Var1;  //可以访问pVar,而修改*pVar便会报错 

大多数人估计研究到这里就截止了,其实以上仅仅只是一级指针,而对于多级指针又会有这样的实现技巧吗?

同样还是:'const右侧的标识什么,什么就不能被直接修改',比如下面:

1const int * const * const pVar = 0xxxxxxxx;   //全都不能修改 
2      int * const * const pVar = 0xxxxxxxx;   //仅**pVar能够修改 
3const int *  * const pVar = 0xxxxxxxx;        //仅*pVar能够修改 

04

const的应用

图片
小哥觉得const主要规范的是一种数据的权限问题 -- 只读,这样就为相关数据的安全性提供了保障,最常用的是与函数的形参配合,从而可以在一定程度上防止被函数内部无故修改,认为是输入参数,比如经常看到的形式:

1int sMempy(const int * pSrc, int * pDst)
2{
3    ////......
4} 

同时由于const修饰的变量为只读属性,所以在单片机中一般会把const修饰的变量放在Flash中,仅供程序读取,这样在一定程度上能够节省RAM内存。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多