关键字
- 一."令人误解"的关键字—const
- 1.const的基本特质
- 2.const的各种应用场景
- 1.修饰变量
- 2.修饰数组
- 3.修饰指针
- 4.修饰函数的参数
- 5.修饰返回值
- 二.最易变的关键字—volatile
一."令人误解"的关键字—const
1.const的基本特质
简单的示例
const所修饰的变量不可像上面那样被直接修改,那它可不可以被间接修改呢?
答案是可以的,能够通过指针的方式进行间接的修改
结论:const修饰的变量并非真的不能被改变
那么const的意义何在呢?
1.让编译器进行直接修改式的检查(如果被直接改变量被直接修改了,会报错方便我们找错)
2.直观的告诉程序员,这个变量不要改
换句话说const只是一种弱型约束,更多的起一个提醒的作用
const修饰的变量在很多时候被认为是常量,但其实它虽然具备常量的一些特征,但它依然不属于常量,看下面例子
在VS中,数组的大小只能用1,2,3这样的数字或者宏定义来表示,从这也可以侧面看出const所修饰的变量并不是常量
2.const的各种应用场景
1.修饰变量
这上文已经说明了,就不再重复
2.修饰数组
跟修饰变量一样的原理,用const修饰数组后,数组内的每一个元素都不能被修改
3.修饰指针
这里如果对于指针还不够了解的话可以看看这篇博客 什么是指针,接下来逐个解析
第一种情况
这里我们很明显能看到改*p是不行的,也就是如果const这么放,说明 * p是不能改的,但p是可以改的
这样写也是一样的效果
情况二
情况三
4.修饰函数的参数
这种写法其实是一种预防性编程,你可以看看库函数里的参数几乎都使用了const,理论上你不加conset也能编译,但加上conset就是为了防止程序员不小心改变了参数 ,从而造成错误,总的来说这是一种好的编程习惯
5.修饰返回值
这里会给出警告,告诉我们应当加上const,保持类型一致
加上以后就能防止我们误改返回值
总之,在返回值上加conset就是为了避免程序员误改函数返回值,从而造成错误(一般用来修饰指针函数,像内置函数(int…)编译器是不会警告的,因为没有意义)
二.最易变的关键字—volatile
翻译一下就是如果不用这个关键字,那么编译器很有可能将我们的代码进行一些优化,那么有可能你的代码就会出现问题,而volatile就是禁止编译器进行优化(目前我们所写的程序都是单进程所以不必用到这个关键字,但如果在双进程程序里就有可能会用到它)
这里举一个不是很恰当的例子
如果flag等于1,那么每进行一次循环,cpu都会判断一次是否成立,就是循环一次,将flag的值拿到cpu里判断一次。因为flag的值是没有改变的,而这样做会比较繁琐,故编译器进行优化,直接将flag的值放到寄存器内,每次检测cpu只需要检测寄存器内的值就可以了。相当于cpu就不会读取编译器里的flag的值(这种情况也被叫做内存覆盖)。当然现在看是没问题的,因为目前只是单线程,当有多线程操作时,有可能flag的值会被其他的”流“所修改,但此时cpu不会读取编译器里的flag数据。换句话说有可能flag已经被改为0了,而cpu读取的依然是1,所以会发生错误
所以为什么volatile"冷门"呢?因为目前我们不会存在while(1)在循环时,突然1被改为0的情况,因为我们是单线程
ps:以上的例子其实有许多漏洞,但只是为了方便我们理解。具体的实验太复杂了,涉及到汇编和Linux的操作,故不再演示
有可能我们会遇到这样的代码,从字面意思上来看,const是保持,要求我们不要改变a,而volatile是易变,又要求改变a,是不是发生矛盾了呢?其实并不是的
const考虑的是如何写,volatile考虑的是如何读,这当然不发生冲突啦