const与volatile

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和volatie

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=0;
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。

原文地址:https://www.cnblogs.com/dongry/p/10239263.html

时间: 2024-11-09 03:44:34

const与volatile的相关文章

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

在C++中,存在类型转换,通常意味着存在缺陷(并非绝对).所以,对于类型转换,有如下几个原则:(1)尽量避免类型转换,包括隐式的类型转换(2)如果需要类型转换,尽量使用显式的类型转换,在编译期间转换(3)避免使用reinterpret_cast和老式的强制类型转换操作符通常,隐式的类型转换会导致警告,需要重视这些警告,并使用显式的类型转换代替,例如static_cast代替一些算术类型转换. 在C++中,对象的类型通常有如下几种:(一)内置类型,如int ,bool ,枚举类型等(二)自定义类型

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

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

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

1.C语言规定只有相同类型的指针才可以相互赋值. Void*指针作为左值用于接收任意类型的指针, void*指针作为右值赋给其他指针时需要强制类型转换. 2.在C语言中Const修饰的变量是只读的,本质还是变量. 口诀:左数右指  不可改变: 当Const出现在*号左边时,指针指向的数据为常量. 当Const出现在*号右边时,指针本身为常量. const int* p ; //P可变,P指向的内容不可变 int const * p; //跟上一句一样 int *const p; //p不可变,p

const,volatile,static,typdef,几个关键字辨析和理解

1.const类型修饰符 const它限定一个变量初始化后就不允许被改变的修饰符.使用const在一定程度上可以提高程序的安全性和可靠性.它即有预编译命令的优点也有预编译没有的优点.const修饰的变量被编译器处理只读变量(不是常量,常量是放到内存的只读区域的)放在内存中,由编译器限定不允许改变. (1)具有不可变性.  例如:const int Max=100; Max++会产生错误; (2)便于进行类型检查,使编译器对处理内容有更多了解,消除了一些隐患. 例如: void f(const i

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

  const.volatile.mutable的用法 鸣谢作者: http://blog.csdn.net/wuliming_sc/article/details/3717017 const修饰普通变量和指针 const修饰变量,一般有两种写法: const TYPE value; TYPE const value; 这两种写法在本质上是一样的.它的含义是:const修饰的类型为TYPE的变量value是不可变的.对于一个非指针的类型TYPE,无论怎么写,都是一个含义,即value值不可变. 

const和volatile同时修饰同一个变量

主要要搞清楚 编译期 和 运行期的关系. 编译期就是 C 编译器将 源代码转化为 汇编再到机器代码 的过程. 运行期就是 实际的机器代码在CPU执行 的过程.很多书上说的东西,其实都只是指编译期进行的事情.const 和 volatile 也一样,所谓的 const ,只是告诉编译器要保证在 C的"源代码"里面,没有对该变量进行修改的地方,就是该变量不能而出现在赋值符号左边.实际运行的时候则不是 编译器 所能管的了.同样,volatile的所谓"可能被修改",是指&

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

原文:C语言中关键字auto.static.register.const.volatile.extern的作用 关键字auto.static.register.const.volatile.extern 这些关键词都是c++基础知识,我整理了一下,希望对新学的朋友们有用: (1)auto 这个这个关键字用于声明变量的生存期为自动,即将不在任何类.结构.枚举.联合和函数中定义的变量视为全局变量,而在函数中定义的变量视为局部变量.这个关键字不怎么多写,因为所有的变量默认就是auto的. (2)reg

C之 const 和 volatile(九)

在  C 语言中,我们经常会见到 const 和 volatile 这两个关键字,那么我们今天就来介绍下这两个关键字. 先来介绍 const 关键字.提起 const 关键字,我们可能首先想到的是经过它修饰的变量便是常量了.其实我们这种想法是错误的,其实 const 修饰的变量是只读的,其本质还是变量.它修饰的局部变量是在栈上分配空间的,它修饰的全局变量在全局数据区分配空间(也就是我们平时所说的 read-only data 段),const 只在编译期有用,在运行期无效.注意:const 修饰

const和volatile的区别

一.关键字const有什么含意? 只要一听到说:“const意味着常数”,就知道我正在和一个业余者打交道.去年Dan Saks已经在他的文章里完全概括了const的所有用法,因此ESP(译者:Embedded Systems Programming)的每一位读者应该非常熟悉const能做什么和不能做什么.如果你从没有读到那篇文章,只要能说出const意味着“只读”就可以了.尽管这个答案不是完全的答案,但我接受它作为一个正确的答案.(如果你想知道更详细的答案,仔细读一下Saks的文章吧.)如果应试