若能避开猛烈的狂喜,自然不会有悲痛来袭。
– 太宰治 《人间失格》
一、概述
const
,源自单词 constant
,有“恒定的;不变的
”的意思,用它来修饰变量,赋予变量只读属性。
const
修饰的变量只能在定义的时候初始化,我们无法在后续的程序中修改其对应或指针指向的值,
请记住,它是只读变量,依然还是变量,而非常量。
区别于常量,一个最重要的不同点是,使用 const
修饰的只读变量不具有“常量表达式”的属性,因此无法用来表示定长数组大小,或使用在 case
语句中。常量表达式本身会在程序编译时被求值,而只读变量的值只能够在程序实际运行时才被得知。并且,编译器通常不会对只读变量进行内联处理,因此其求值不符合常量表达式的特征。
二、使用说明
- 常规用法,由于定义之后不能改变其值,效果类似宏定义,这种方法相较于宏定义的好处在于:编译器可以对其进行数据类型安全检查,也方便调试。
//两个方法效果一样(记得定义的时候就需要初始化)
int const a = 10;
const int a = 10;
- 修饰指针(如何记,看章节四)
//两者相同,指针的指向的值不可以修改
const int *p;
int const *p;
//含义是常量指针,p 的值不可以修改,指向的值可以修改
int * const p;
//指针不可以修改,指向的值也不可以修改
int * const *p;
- 用于函数形参,
const
最常被使用的地方
//const用于形参时说明了形参在函数内部不会被改变,限定函数的形参,该函数将不能修改实参指针所指向的数据。
void foo(const int * p)
三、温馨提示
- 在一些单片机系统中,使用
const
修饰的变量(比较常见的是数组),其值是保存在FLASH
中的,读取的时候直接从FLASH
中读取,不会占用内存(RAM
)的空间,大大节省了内存的使用,尤其是一些固定数据的数组(某些表),节省内存的效果非常明显。 const
修饰函数的参数,是不希望外部函数改变该参数的值,如果函数内有修改的操作,则会报错。- 如果给以“指针传递”方式的函数返回值加 const 修饰,那么函数返回值(即指针)的内容不能被修改,该返回值只能被赋给加
const
修饰的同类型指针。比如const char * func(void)
,必须使用const char *str = func();
。不过这种方式比较少用,了解就好。 - 在修饰指针时,先将类型名去掉,然后看
const
修饰的是谁,则谁是不允许改变的。
比如const int * p
,看成const *p
,可以知道修饰的是*p
,也就是指针p
指向的值,也就是p
指向的值是不能修改的, 比如*p = 2
这种操作是不允许的。
又比如int * const p
,看成* const p
,可以知道修饰的是p
,也就是p
的值是不能修改的,p = 0xff
是不允许的。
四、const关键字修饰指针速记的好方法
const
关键字起到某些值不被修改的作用。首先const int a 和int const a是一样的,也就是说const在类型前后对变量没啥影响。
但是对于下面两组,相信很多人和之前的我一脸懵逼。
-
int const *p;
-
int *const p;
首先,我们知道 p
一定是个指针,但是哪一个要求不能修改指针的值?哪一个不能修改指针所指向的值呢?
其实我们可以这样记:
对于第一组,const
修饰的是 *p
,而我们知道 *p
指的是指针p所指向的值,则说明 const
修饰的是指针 p
所指向的值,所以对于第一组,你可以修改指针的值,但是你不能修改指针所指向的值。
对于第二组,const
修饰的是 p
,而 p
是指针,所以你不能修改这里的指针 p
的值,但是你能够修改指针 p
所指向的值
。
当然对于 int const *const p
,两者你都不能改变。
更多精彩内容,请关注公众号《嵌入式小散修》。