const 和 const volatile 的区别

Posted

技术标签:

【中文标题】const 和 const volatile 的区别【英文标题】:Difference between const & const volatile 【发布时间】:2011-06-03 07:51:34 【问题描述】:

如果我们在每次更新新值时声明一个变量为volatile 如果我们将变量声明为const,那么该变量的值将不会改变

然后const volatile int temp; 像上面那样声明变量temp有什么用? 如果我们声明为const int temp,会发生什么?

【问题讨论】:

你不会在块范围内使用const volatile int temp;(即在 内),它在那里没有用处。 【参考方案1】:

标记为const volatile 的对象不允许被代码更改(由于const 限定符将引发错误)- 至少通过该特定名称/指针。

限定符的volatile 部分意味着编译器无法优化或重新排序对对象的访问。

在嵌入式系统中,这通常用于访问硬件寄存器,这些寄存器可以被硬件读取和更新,但写入没有意义(或者写入可能出错)。

一个例子可能是串行端口的状态寄存器。各种位将指示一个字符是否正在等待读取,或者发送寄存器是否准备好接受一个新字符(即 - 它是空的)。每次读取此状态寄存器都可能导致不同的值,具体取决于串行端口硬件中发生的其他情况。

写入状态寄存器是没有意义的(取决于特定的硬件规格),但您需要确保每次读取寄存器都会导致实际读取硬件 - 使用来自前一个缓存的值read 不会告诉你硬件状态的变化。

一个简单的例子:

unsigned int const volatile *status_reg; // assume these are assigned to point to the 
unsigned char const volatile *recv_reg;  //   correct hardware addresses


#define UART_CHAR_READY 0x00000001

int get_next_char()

    while ((*status_reg & UART_CHAR_READY) == 0) 
        // do nothing but spin
    

    return *recv_reg;

如果这些指针未标记为volatile,则可能会出现几个问题:

while 循环测试可能只读取状态寄存器一次,因为编译器可以假定它指向的任何内容都不会改变(while 循环测试或循环本身没有任何东西可以改变它)。如果您在 UART 硬件中没有字符等待时输入该函数,您可能会陷入一个即使接收到一个字符也不会停止的无限循环。 接收寄存器的读取可以由编译器移动到 while 循环之前 - 再次因为函数中没有任何内容表明 *recv_reg 被循环更改,没有理由不能在之前读取进入循环。

volatile 限定符确保编译器不会执行这些优化。

【讨论】:

+1 用于解释。我有一个问题: const volatile 方法呢?如果我有一个由许多线程访问的类(尽管访问与互斥锁同步),我的 const 方法是否也必须是 volatile 的(因为某些变量可能会被其他线程更改)【参考方案2】: volatile 将告诉编译器不要优化与变量相关的代码,通常当我们知道它可以从“外部”更改时,例如由另一个线程。 const 会告诉编译器禁止程序修改变量的值。 const volatile 是一个非常特别的东西,你可能会在你的生活中看到恰好被使用 0 次 (tm)。正如所料,这意味着程序无法修改变量的值,但可以从外部修改该值,因此不会对变量进行优化。

【讨论】:

我原以为volatile 变量通常是在您开始弄乱硬件而不是其他线程时发生的。我见过const volatile 使用的地方是内存映射状态寄存器等。 当然,你说得对,多线程只是一个例子,但不是唯一的:)。 如果您使用嵌入式系统,您会经常看到这种情况。【参考方案3】:

不是因为变量是 const,它可能在两个序列点之间没有变化。

常量是你做出的不改变价值的承诺,而不是价值不会改变的承诺。

【讨论】:

加一个指出const 数据不是“恒定的”。【参考方案4】:

在 C 中,constvolatile 是类型限定符,这两个是独立的。

基本上,const 表示程序无法修改该值。

volatile 表示该值可能会突然发生变化(可能来自程序外部)。

事实上,C 标准给出了一个有效声明的例子,它是constvolatile。例子是:

extern const volatile int real_time_clock;

其中real_time_clock 可以通过硬件修改,但不能分配、递增或递减。

所以我们应该已经分别对待constvolatile。这些类型限定符也可以应用于structunionenumtypedef

【讨论】:

【参考方案5】:

我需要在嵌入式应用程序中使用它,其中一些配置变量位于闪存区域中,可由引导加载程序更新。这些配置变量在运行时是“恒定的”,但如果没有 volatile 限定符,编译器会优化这样的东西......

cantx.id = 0x10<<24 | CANID<<12 | 0;

...通过预先计算常量值并使用立即汇编指令,或从附近位置加载常量,这样对配置闪存区域中原始 CANID 值的任何更新都将被忽略。 CANID 必须是 const volatile。

【讨论】:

【参考方案6】:

您可以同时使用constvolatile。例如,如果0x30 被假定为端口的值 仅由外部条件改变,以下声明将防止任何可能性 意外的副作用:

const volatile char *port = (const volatile char *)0x30;

【讨论】:

【参考方案7】:

const表示该变量不能被c代码修改,并不是不能改变。这意味着没有指令可以写入变量,但它的值可能仍然会改变。

volatile 表示该变量可能随时更改,因此可能不会使用缓存值;对变量的每次访问都必须执行到它的内存地址。

由于问题被标记为“嵌入”并且假设 temp 是用户声明的变量,而不是与硬件相关的寄存器(因为这些通常在单独的 .h 文件中处理),请考虑:

同时具有易失性读写数据存储器 (RAM) 和非易失性只读数据存储器的嵌入式处理器,例如冯诺依曼架构中的 FLASH 存储器,其中数据和程序空间共享公共数据和地址总线.

如果你声明const temp有一个值(至少如果不为0),编译器会将变量分配给FLASH空间中的地址,因为即使分配给RAM地址,它仍然需要FLASH内存来存储变量的初始值,由于所有操作都是只读的,因此使RAM地址浪费空间。

结果:

int temp;是存储在RAM中的变量,启动时初始化为0(cstart),可以使用缓存值。

const int temp;是存储在(只读)FLASH中的变量,编译时初始化为0,可以使用缓存值。

volatile int temp; 是存储在 RAM 中的变量,在启动(cstart)时初始化为 0,不会使用缓存的值。

const volatile int temp;是存储在(只读)FLASH中的变量,编译时初始化为0,缓存值不会被使用

有用的部分来了:

如今,大多数嵌入式处理器都能够通过特殊功能模块对其只读非易失性存储器进行更改,在这种情况下,const int temp 可以在运行时更改,但不能直接更改。换句话说,一个函数可以修改temp所在地址的值。

一个实际的例子是使用temp 作为设备序列号。嵌入式处理器第一次运行时,temp 将等于 0(或声明的值),并且函数可以使用此事实在生产期间运行测试,如果成功,则要求分配序列号并修改值temp 的特殊功能。一些处理器有一个特殊的地址范围,带有 OTP(一次性可编程)内存,仅用于此目的。

但这里有区别:

如果const int temp 是可修改 ID 而不是一次性可编程序列号并且未声明为 volatile,则可能会使用缓存值直到下一次启动,这意味着新 ID 可能直到下次重新启动,或者更糟糕的是,某些函数可能会使用新值,而其他函数可能会使用旧的缓存值,直到重新启动。 如果const int temp被声明为voltaile,则ID更改将立即生效。

【讨论】:

哇这个答案好长【参考方案8】:

本文讨论了您想要组合 const 和 volatile 限定符的场景。

http://embeddedgurus.com/barr-code/2012/01/combining-cs-volatile-and-const-keywords/

【讨论】:

【参考方案9】:

简单来说, 'const volatile' 变量中的值不能以编程方式修改,但可以通过硬件修改。这里的volatile是为了防止任何编译器优化。

【讨论】:

【参考方案10】:

当我们不想让程序更改变量时,我们使用“const”关键字来表示变量。而当我们声明一个变量“const volatile”时,我们是在告诉程序不要更改它,并且告诉编译器这个变量可能会因来自外部世界的输入而意外更改。

【讨论】:

以上是关于const 和 const volatile 的区别的主要内容,如果未能解决你的问题,请参考以下文章

const volatile int i

C之 const 和 volatile

第9课 const和volatile分析

volatile与const综合分析

C语言学习笔记--const 和 volatile关键字

volatile 如何与 const 一起工作?