1. const关键字

  【1】const限制一个变量不能修改其内容,如果强行修改的话,如下面代码这样子,编译就会报错,“表达式必须是可修改的左值”。

const int a = 6;
a = 10;

   【2】如果按如下方式通过指针强行修改,编译可以通过,但是std::cout的话,a的值还是6,但是*p是12,这是因为,编译器对于const类型的变量不会二次读取,只会在最开始的时候从内存中读取一次,之后存储在常量表,之后需要用到就从常量表中取得。

const int a = 6;
int* p = (int*)&a;
*p = 12;

   【3】常量指针:指向常量的指针,也就是指针指向的是一个常量,值不可以改变,但是指针本身地址可以改变,可以指向其他地址,下面两种定义方式都对:

const int* p1;
int const* p2;

   指针常量:指针地址是个常量,指针本身地址不能改变,但是指针指向的变量的值可以改变,只有一种写法如下:

int a = 2;
int* const p3 = &a;

   指针常量是int类型的指针,定义的时候必须初始化地址。

   【4】 const用于聚合,表示“不能改变的一块地址”,但是不能再编译期间使用它的值,因为编译器在编译期间不需要知道存储的内容,也就是下面的代码中有两句是非法的:

const int i[]={ 1, 2, 3, 4 };
float f[i[3]];//Illegal
struct S { int i, j;};
const S s[]=d[s[1].j];//Illegal

  【5】C语言默认const为外部链接,所以代码const int bufsize=100;char buf[bufsize]是错误的,因为bufsize占用某块内存,而编译器不知道它在编译时的值。C中可以这样写const int bufsize;,但这在C++中是错误的,因为C++默认const为内部链接,必须在定义时初始化。

  【6】C++中定义const指定为外部链接有两种方式:1)extern const int x=1;,这样初始化并指定为extern,强迫编译器给x分配内存(事实上编译器这里仍然可能选择常量折叠),初始化使它成为一个定义而非声明。2)extern const int x;,意味着在别处进行了定义(C中这总是一个定义,所以不一定在别处进行了定义),C++中使用extern const却不初始化,那么编译器就不能使用常量折叠而必须分配内存。

  【6】const代替宏定义以消除宏的不安全性:

#define A1 100.5
const int A2=100.5;
char P1[A1];//Illegal
char P2[A2];//OK

【7】const必须在建立它的时候被初始化,但是在类中使用一个非static的const时(static const必须在建立时初始化),不能给他初值,初始化必须在构造函数中进行。这两件事情的矛盾可以由构造函数初始化列表解决,如下:

class A{const int a;
public:A(int aa);void print();
};
A::A(int aa):a(aa){}
void A::print(){cont<<aa<<endl;}
int main(){A a(1),b(2);a.print();b.print();
}

2. volatile关键字

  这个关键字的作用在于告诉编译器这个变量可变,不要对其进行优化。因为通常来说,编译器会对代码进行优化。比如下面的代码:

volatile int i = 10;
int a = i;
...// 其他代码,并未明确告诉编译器,对 i 进行过操作
int b = i;

  volatile 指出 i 是随时可能发生变化的,每次使用它的时候必须从 i的地址中读取,因而编译器生成的汇编代码会重新从i的地址读取数据放在 b 中。而优化做法是,由于编译器发现两次从 i读数据的代码之间的代码没有对 i 进行过操作,它会自动把上次读的数据放在 b 中。而不是重新从 i 里面读。这样以来,如果 i是一个寄存器变量或者表示一个端口数据就容易出错,所以说 volatile 可以保证对特殊地址的稳定访问。但是,在 VC 6 中,一般调试模式没有进行代码优化,所以这个关键字的作用看不出来。如下代码:

int i = 10;
int a = i;
printf("i = %d", a);
// 下面汇编语句的作用就是改变内存中 i 的值但是又不让编译器知道
__asm {mov dword ptr[ebp - 4], 20h
}
int b = i;
printf("i = %d", b);

  debug模式输出10和32,但是release模式输入10和10。其可以确保每次使用变量的时候,都从内存中重新读取,而不允许编译器对这个变量的读取操作进行优化。一般在多任务环境下会用到这个关键字。

  与const类似,有:

volatile int* p1;//volatile int类型的指针,禁止编译器优化指针指向的变量,但是可以优化指针本身地址
int volatile* p2;//同上,另一种写法int* volatile p3;//int类型的指针,禁止编译器优化指针本身地址,但是可以优化指针指向的变量

  多线程环境下有些变量是用volatile关键字声明的。当两个线程都要用到某一个变量且该变量的值会被改变时,应用volatile声明,该关键字的作用是防止优化编译器把变量从内存装入CPU寄存器中。如果变量被装入寄存器,那么两个线程有可能一个使用内存中的变量,一个使用寄存器中的变量,这会造成程序的错误执行。volatile的意思是让编译器每次操作该变量时一定要从内存中真正取出,而不是使用已经存在寄存器中的值,如下:

volatile  BOOL  bStop = FALSE;
//(1) 在一个线程中:
while (!bStop) { ... }
bStop = FALSE;
return;
//(2) 在另外一个线程中,要终止上面的线程循环:
bStop = TRUE;
while (bStop);
//等待上面的线程终止,如果bStop不使用volatile申明,那么这个循环将是一个死循环,因为bStop已经读取到了寄存器中,
//寄存器中bStop的值永远不会变成FALSE,加上volatile,程序在执行时,每次均从内存中读出bStop的值,就不会死循环了。

欢迎扫描二维码关注微信公众号 深度学习与数学   [每天获取免费的大数据、AI等相关的学习资源、经典和最新的深度学习相关的论文研读,算法和其他互联网技能的学习,概率论、线性代数等高等数学知识的回顾]

【一天一个C++小知识】002.C++中const和volatile关键字相关推荐

  1. 【每天一个Python小知识】NumPy中的np.where

    函数形式:a = np.where(b) 功能:找到满足条件的b的索引a. 参数:b是某种条件,要求是np类型. 返回值:a是返回的索引,也是np类型. 举个套娃的例子来更好的了解这个函数: impo ...

  2. 【每天一个Python小知识】NumPy中的np.any

    import numpy as np np.any(np.array) 对矩阵中所有元素做或运算,存在True则返回True 一般在条件判等时使用,如: import numpy as np a = ...

  3. 安卓期末作品小项目_每日一个财务小知识——洞悉洞晰财务报告第一季

    财务报告 洞悉洞晰财务报告 目录 01/账务报告概述 02/资产负债表 03/利润表 04/现金流量表 05/所有者权益变动表 06/附注 一.财务报告概述 (一)财务报告及其目标 财务报告是指企业对 ...

  4. 【C#小知识】C#中一些易混淆概念总结(三)---------结构,GC,静态成员,静态类...

    目录: [C#小知识]C#中一些易混淆概念总结 [C#小知识]C#中一些易混淆概念总结(二) ---------------------------------------分割线----------- ...

  5. 【C#小知识】C#中一些易混淆概念总结(七)---------解析抽象类,抽象方法

    目录: [C#小知识]C#中一些易混淆概念总结--------数据类型存储位置,方法调用,out和ref参数的使用 [C#小知识]C#中一些易混淆概念总结(二)--------构造函数,this关键字 ...

  6. 奶粉中的php是什么,奶粉小知识:奶粉中的OPO起到什么作用?

    原标题:奶粉小知识:奶粉中的OPO起到什么作用? 现在不少奶粉都打着OPO的名号作为宣传卖点,那么,OPO在奶粉中到底到了什么作用,却仍然有着大部分人不太了解. 实际上,OPO,又称OPO结构脂,是一 ...

  7. 【每天一个Python小知识】用yaml的yaml.safe_load()方法读取配置文件中的参数

    文章目录 ymal安装 配置文件格式 配置文件读取 yaml是专门用来写配置文件的,因其简洁高效而被大众喜爱. ymal安装 python3安装: pip install pyyaml#python2 ...

  8. list赋值给另一个list_Python小知识: List的赋值方法,不能直接等于

    Python中关于对象复制有三种类型的使用方式,赋值.浅拷贝与深拷贝.他们既有区别又有联系,刚好最近碰到这一类的问题,研究下. 一.赋值 在python中,对象的赋值就是简单的对象引用,这点和C++不 ...

  9. 每天一个shell小知识(shell变量)

    目录 shell变量 自定义变量: 变量定义/查看 变量赋值的特殊操作: 双引号 单引号 反撇号 设置变量的作用范围: 特殊变量---环境变量: 位置变量: 预定义变量: shell变量 在各种she ...

  10. 每天一个shell小知识(for)

    目录 For循环语句 For语句的结构 结构 执行流程 实例 For循环语句 在实际工作环境中,经常会遇到某项任务需要多次执行的情况,而每次执行时仅仅是处理的对象不一样,其他命令完全相同.如:根据服务 ...

最新文章

  1. 5万字的《Java面试手册》V1.0版本,高清PDF免费获取
  2. 未来十年有望改变世界的五大发现
  3. Python常见问题(6):Python在Windows上的问题 Python on Windows FAQ
  4. [云炬创业管理笔记]第四章把握创业机会测试5
  5. STL源码剖析 第七章 仿函数(函数对象)
  6. asp.net core权限模块的快速构建
  7. JSON数据格式----- JavaScript与JSON、JavaScript的JSON对象、构建JSON格式数据
  8. 7-34 红色警报 (10 分)(结构体并查集)
  9. 转载---KMP算法(Matrix67原创)
  10. 12-Python3 元组
  11. python学习笔记4-切片
  12. Origin Pro2022教育版官方申请、安装及汉化、续期
  13. 【翻译】Ionic的刷新器-Refresher官方文档翻译
  14. 生鲜电商的“7年之谎”
  15. codesensor:将代码转化为ast后再转化为文本向量
  16. 【Office】三件套之Word套路
  17. php最短路径tsp,最短路径tsp算法
  18. 《货币金融学》第七版
  19. Python:flake8_E501_E128_E125
  20. *CF1216F. Wi-Fi (dp)

热门文章

  1. MySQL服务端恶意读取客户端文件漏洞 (DDCTF2019和国赛均涉及到这个漏洞)
  2. 2018.12.12 第九章虚拟内存
  3. SharePoint Online 自定义Modern UI表单
  4. 洛谷 P4568 [JLOI2011]飞行路线
  5. select机制的原理
  6. C# 高效字符串连接 StringBuilder介绍
  7. Ubuntu安装Atom编辑器
  8. 微信小程序——诉讼费计算
  9. ZeroClipboard—ZeroClipboard的使用
  10. yii2 中 controller 向layout 传值