C或者C++基本上是按照从上到下、从左至右的顺序来读。但对于指针声明从某种意义上来讲是倒着的。

C或者C++中每个声明都由两部分组成:零个或者多个声明说明符,一个或者多个用逗号隔开的声明符。

const

1.类型说明符表明声明符ID的类型;其他说明符提供直接适用于这个声明符ID的一些类型无关的信息。

eg1.static unsigned long int *x[N];

声明x的类型是“指向unsigned long int的N个指针元素的序列”。关键词static表明x有静态分配的存储空间。

eg2.const void *vetorTable[]={...data...};

const没有直接适用于vectorTable,而是适用于void。这句声明表示vectorTable的类型是“指向const void的指针序列”。但是明显你希望它是“指向void的指针的const序列”。

2.声明说明符在一个声明中出现的顺序并不重要

eg1. VP const vectorTable[] 等同于 const VP vectorTable[]

eg2. void const *vectorTable[] 等同于 const void *vectorTable[]

3.声明说明符const和volatile不寻常,因为:能出现在声明符中的声明说明符只有const和volatile

eg1.void *const vectorTable[] //const出现在声明符中,这种情况不能重排关键字顺序

*const void vectorTable[]是错误的;

4.指针的声明是从右到左来看。把const放在其他类型说明符的右边,可以严格的从右到左来看指针声明,还可以把const从“右边的”位置提出来

eg1. T const *p //把p声明为"指向const T的指针";

eg2. T *const p //把p声明为"指向T的const指针";

5.把const写在其他声明说明符的右边,实际上可以更容易的看出const和类型名称相结合的效果

原始eg.typedef void *VP;

const VP vectorTable[];

eg1.const VP vectorTable[];

const void *vectorTable[]; //错误,vectorTable声明为"指向const void"的指针数组;

eg2.const VP vectorTable[];

void *const vectorTable[];//指向"void的const指针数组"

eg3.VP const vectorTable[];   //声明说明符在声明中出现的位置不重要

void *const vectorTable[];

6.实际例子

const int a;   //声明一个常整型数a

int const a;   //声明一个常整型数a

const int *a;  //a为指向const int的指针(整型数是不可以修改的,但指针a可以修改)

int *const a;  //a为指向int的const指针(指针指向的整型数可以修改,但指针a不可以修改)

int const *const a;  //a为指向const int的const指针(指针指向的整形数与指针都不可以修改)

volatile

1.volatile的使用

volatile 关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改,比如:操作系统、硬件或者其它线程等。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。当要求使用volatile声明的变量的值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。而且读取的数据立刻被保存。

volatile int i=;
int a=i;
..... //中间没有使用到i
int b=i;

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

volatile的应用:

1)中断服务程序中修改的供其他程序检测的变量需加volatile(中断服务的子程序中访问到的非自动变量)[自动变量即局部变量]

2)多任务坏境下各任务之间共享的标志需加volatile

3)存储器映射的硬件寄存器通常也要加volatile说明,因为每次读写都可能有不同的意义

2.volatile指针

1)可以把一个非volatile int赋给volatile int,但是不能把非volatile对象赋给一个volatile对象。

2)除了基本类型外,对用户定义类型也可以用volatile类型进行修饰。

3)https://www.cnblogs.com/zhaoli/p/4250468.html

3.多线程下的volatile

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

volatile BOOL bStop=FALSE;

在一个线程中

while(!bStop)
{
....
}
bStop=FALSE;
return;

在另一个线程中,要终止上面线程的循环

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

4 问题

eg1.一个参数既可以是const还可以是volatile吗,为什么?

答:是的。一个例子是只读的状态寄存器。它是volatile因为它可能被意想不到地改变。它是const因为程序不应该试图去修改它

eg2.一个指针可以是volatile吗,为什么?

答:是的。尽管这并不很常见。一个例子是当一个中服务子程序修该一个指向一个buffer的指针时。

eg3.下面代码中的错误

int square(volatile int *ptr)
{
return *ptr**ptr;
}

这段代码的目的是用来返回指针*ptr指向值的平方,但是由于*ptr指向一个volatile型参数,编译器将产生类似下面的代码:

int square(volatile int *ptr)
{
int a,b;
a=*ptr;
b=*ptr;
return a*b; //由于*ptr的值可能被意想不到地改变,因此a和b可能是不同的
}

正确的是:

long square(volatile int *ptr)
{
int a;
a=*ptr;
return a*a;
}

eg4.假如你向一个寄存器进行写操作,先写0xAA,接着再写0x55,编译器在进行优化的时候有可能认为这个是冗余,所以这时候就需要volatile。

const与volatile的更多相关文章

  1. C++ const、volatile、mutable的用法 (转)

      const.volatile.mutable的用法 鸣谢作者: http://blog.csdn.net/wuliming_sc/article/details/3717017 const修饰普通 ...

  2. C语言中关键字auto、static、register、const、volatile、extern的作用

    原文:C语言中关键字auto.static.register.const.volatile.extern的作用 关键字auto.static.register.const.volatile.exter ...

  3. const、volatile、mutable的用法

    http://blog.csdn.net/wuliming_sc/article/details/3717017 const.volatile.mutable的用法 const修饰普通变量和指针 co ...

  4. C++ 中 const、volatile、mutable的用法

    @2019-01-14 [小记] C++中const.volatile.mutable的用法

  5. 【C】——const和volatile可以并用吗?

    答案是肯定的,可以一起用. 因为很多人误解了const的真正含义,很多初学者认为const修饰的就是常量,而常量不会改变,而既然不会改变,那volatile就没有意义. 但是实际上这正是对const的 ...

  6. void指针意义、Const、volatile、#define、typedef、接续符

    1.C语言规定只有相同类型的指针才可以相互赋值. Void*指针作为左值用于接收任意类型的指针, void*指针作为右值赋给其他指针时需要强制类型转换. 2.在C语言中Const修饰的变量是只读的,本 ...

  7. 【C++】const、volatile不能修饰没有this指针的成员函数

    一般所有的成员函数都只有一个复本,当不同的对象调用成员函数时,为了区分是哪个成员在调用,会传入this指针. 当调用有const.volatile修饰的成员函数时,会相应的传入一个const.vola ...

  8. C++的类型转换:static_cast、dynamic_cast、reinterpret_cast和const_cast(dynamic_cast还支持交叉转换,const_cast将一个类的const、volatile以及__unaligned属性去掉)

    在C++中,存在类型转换,通常意味着存在缺陷(并非绝对).所以,对于类型转换,有如下几个原则:(1)尽量避免类型转换,包括隐式的类型转换(2)如果需要类型转换,尽量使用显式的类型转换,在编译期间转换( ...

  9. 第9课 - const 和 volatile分析

    第9课 - const和volatile分析 1. const只读变量 (1)const修饰的变量是只读的,本质上还是变量,并不是真正意义上的常量         ※※ const只是告诉编译器该变量 ...

随机推荐

  1. python学习中的bug

    1.在pycharm的terminal中的python工程目录下update pip失败,但是在cmd中为什么就可以.’

  2. 1.3 flask

    2019-1-3 12:03:55 还是天天看视频,敲代码感觉好! 越努力,越幸运! flask 部分参考连接  https://www.cnblogs.com/wupeiqi/articles/75 ...

  3. poj 1873

    哇实验室里正在吵架,爽死了! wf水题.显然二进制枚举,注意剪枝,val>ans的时候剪一下,不然会tle.然后就没惹. 我老人家一开始写了个 感觉非常垃圾,wa了一发又t了一发. 感觉自己可以 ...

  4. JWT(Json Web Token—)的定义及组成

    JWT定义及其组成 JWT(JSON Web Token)是一个非常轻巧的规范.这个规范允许我们使用JWT在用户和服务器之间传递安全可靠的信息. 一个JWT实际上就是一个字符串,它由三部分组成,头部. ...

  5. js中级小知识5

    元素的属性 div.attributes是所有标签属性构成的数据集合 div.classList是所有class名构成的数组集合 在classList的原型链上可以看到add()和remove() 1 ...

  6. ubuntu14.04 LTS 更新国内网易163源

    2015/10/7 更改ubuntu的默认源是linux学习中必须掌握的基础技能.在此记录,以作参考. 在ubuntu14.04 LTS默认使用的是国外源,由于网络的原因,使用apt-get安装包时异 ...

  7. python文件派生

    import time class Foo: x = 1 def __init__(self, y): self.y = y def __getattr__(self, item): # 没有的情况下 ...

  8. 并行开发-Paraller

    并行开发的概念 并行开发要做的事情就是将任务分摊给硬件线程去并行执行来达到负载和加速,传统的代码都是串行的,就一个主线程,当我们为了实现加速而开了很多工作线程,这些工作线程就是软件线程 Paralle ...

  9. Spring Data JPA框架

    1.前言 扔一个 spring data jpa 的代码,可运行,后续补充博客内容. 环境:eclipse + tomcat8 2.部分截图 3.源码 https://gitee.com/niceyo ...

  10. bugfree3.0.1-修改“优先级”为中文引起的PHP Error

    博主在搭建好bugfree后,修改了系统中“优先级”字段,将原先系统定义的优先级“1.2.3.4”修改为符合博主自己项目要求的优先级“高.中.低”.修改成功后,系统确实将原先提交的BUG优先级从“1. ...