简体   繁体   English

const 和 const volatile 之间的区别

[英]Difference between const & const volatile

If we declare a variable as volatile every time the fresh value is updated如果每次更新新值时我们都将变量声明为volatile
If we declare a variable as const then the value of that variable will not be changed如果我们将一个变量声明为const那么该变量的值将不会改变

Then const volatile int temp;然后const volatile int temp;
What is the use of declaring the variable temp as above?如上所述声明变量temp有什么用?
What happens if we declare as const int temp ?如果我们声明为const int temp会发生什么?

An object marked as const volatile will not be permitted to be changed by the code (an error will be raised due to the const qualifier) - at least through that particular name/pointer.代码不允许更改标记为const volatile的对象(由于const限定符将引发错误)-至少通过该特定名称/指针。

The volatile part of the qualifier means that the compiler cannot optimize or reorder access to the object.限定符的volatile部分意味着编译器无法优化或重新排序对对象的访问。

In an embedded system, this is typically used to access hardware registers that can be read and are updated by the hardware, but make no sense to write to (or might be an error to write to).在嵌入式系统中,这通常用于访问可由硬件读取和更新的硬件寄存器,但写入没有意义(或者可能是写入错误)。

An example might be the status register for a serial port.一个例子可能是串行端口的状态寄存器。 Various bits will indicate if a character is waiting to be read or if the transmit register is ready to accept a new character (ie., - it's empty).各种位将指示字符是否正在等待读取或发送寄存器是否已准备好接受新字符(即 - 它是空的)。 Each read of this status register could result in a different value depending on what else has occurred in the serial port hardware.根据串行端口硬件中发生的其他情况,对该状态寄存器的每次读取都可能导致不同的值。

It makes no sense to write to the status register (depending on the particular hardware spec), but you need to make sure that each read of the register results in an actual read of the hardware - using a cached value from a previous read won't tell you about changes in the hardware state.写入状态寄存器是没有意义的(取决于特定的硬件规格),但是您需要确保每次读取寄存器都会导致对硬件的实际读取 - 使用先前读取的缓存值将不会' t 告诉您硬件状态的变化。

A quick example:一个简单的例子:

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;
}

If these pointers were not marked as being volatile , a couple problems might occur:如果这些指针没有被标记为volatile ,可能会出现一些问题:

  • the while loop test might read the status register only once, since the compiler could assume that whatever it pointed to would never change (there's nothing in the while loop test or loop itself that could change it). while 循环测试可能只读取状态寄存器一次,因为编译器可以假设它指向的任何东西都不会改变(while 循环测试或循环本身没有任何东西可以改变它)。 If you entered the function when there was no character waiting in UART hardware, you might end up in an infinite loop that never stopped even when a character was received.如果您在 UART 硬件中没有字符等待时进入该函数,您可能会进入一个无限循环,即使接收到一个字符也不会停止。
  • the read of the receive register could be moved by the compiler to before the while loop - again because there's nothing in the function that indicates that *recv_reg is changed by the loop, there's no reason it can't be read before entering the loop.接收寄存器的读取可以由编译器移动到 while 循环之前 - 再次因为函数中没有任何内容表明*recv_reg被循环更改,没有理由在进入循环之前无法读取它。

The volatile qualifiers ensures that these optimizations are not performed by the compiler. volatile限定符确保编译器不会执行这些优化。

  • volatile will tell the compiler not to optimise code related the variable, usually when we know it can be changed from "outside", eg by another thread. volatile会告诉编译器不要优化与变量相关的代码,通常是当我们知道它可以从“外部”更改时,例如通过另一个线程。
  • const will tell the compiler that it is forbidden for the program to modify the variable's value. const会告诉编译器禁止程序修改变量的值。
  • const volatile is a very special thing you'll probably see used exactly 0 times in your life (tm). const volatile是一个非常特别的东西,你可能会在你的生活中看到它使用了 0 次 (tm)。 As is to be expected, it means that the program cannot modify the variable's value, but the value can be modified from the outside, thus no optimisations will be performed on the variable.正如所料,这意味着程序不能修改变量的值,但可以从外部修改该值,因此不会对变量进行优化。

It is not because the variable is const that it may not have changed between two sequence points.并不是因为变量是常量,所以它在两个序列点之间可能没有改变。

Constness is a promise you make not to change the value, not that the value won't be changed. Constness 是你做出的不改变价值的承诺,而不是价值不会改变。

In C, const and volatile are type qualifiers and these two are independent.在 C 中, constvolatile是类型限定符,这两个是独立的。

Basically, const means that the value isn't modifiable by the program.基本上, const意味着该值不能被程序修改。

And volatile means that the value is subject to sudden change (possibly from outside the program).volatile意味着该值会发生突然变化(可能来自程序外部)。

In fact, the C Standard gives an example of a valid declaration which is both const and volatile .事实上,C 标准给出了一个既是const又是volatile的有效声明的例子。 The example is:例子是:

extern const volatile int real_time_clock;

where real_time_clock may be modifiable by hardware, but cannot be assigned to, incremented, or decremented.其中real_time_clock可由硬件修改,但不能分配、递增或递减。

So we should already treat const and volatile separately.所以我们应该已经分别对待constvolatile These type qualifiers can be applied to struct , union , enum and typedef as well.这些类型限定符也可以应用于structunionenumtypedef

I've needed to use this in an embedded application where some configuration variables are located in an area of flash memory that can be updated by a bootloader.我需要在嵌入式应用程序中使用它,其中一些配置变量位于闪存区域,可由引导加载程序更新。 These config variables are 'constant' during runtime, but without the volatile qualifier the compiler would optimise something like this...这些配置变量在运行时是“常量”,但如果没有 volatile 限定符,编译器会优化这样的东西......

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

...by precomputing the constant value and using an immediate assembly instruction, or loading the constant from a nearby location, so that any updates to the original CANID value in the config flash area would be ignored. ...通过预先计算常量值并使用立即汇编指令,或从附近位置加载常量,这样对配置闪存区域中原始 CANID 值的任何更新都将被忽略。 CANID has to be const volatile. CANID 必须是 const 可变的。

const means that the variable cannot be modified by the c code, not that it cannot change. const表示变量不能被 c 代码修改,而不是它不能改变。 It means that no instruction can write to the variable, but its value might still change.这意味着没有指令可以写入变量,但它的值可能仍然会改变。

volatile means that the variable may change at any time and thus no cached values might be used; volatile意味着该变量可能随时更改,因此可能不会使用缓存值; each access to the variable has to be executed to its memory address.对变量的每次访问都必须执行到其内存地址。

Since the question is tagged "embedded" and supposing temp is a user declared variable, not a hardware-related register (since these are usually handled in a separate .h file), consider:由于问题被标记为“嵌入式”并且假设temp是用户声明的变量,而不是与硬件相关的寄存器(因为这些通常在单独的 .h 文件中处理),请考虑:

An embedded processor which has both volatile read-write data memory (RAM) and non-volatile read-only data memory, for example FLASH memory in von-Neumann architecture, where data and program space share a common data and address bus.具有易失性读写数据存储器 (RAM) 和非易失性只读数据存储器的嵌入式处理器,例如冯诺依曼架构中的闪存,其中数据和程序空间共享公共数据和地址总线。

If you declare const temp to have a value (at least if different from 0), the compiler will assign the variable to an address in FLASH space, because even if it were assigned to a RAM address, it still needs FLASH memory to store the initial value of the variable, making the RAM address a waste of space since all operations are read-only.如果你声明const temp有一个值(至少在不等于 0 的情况下),编译器会将该变量分配给 FLASH 空间中的一个地址,因为即使它被分配给一个 RAM 地址,它仍然需要 FLASH 存储器来存储变量的初始值,使 RAM 地址浪费空间,因为所有操作都是只读的。

In consequence:结果:

int temp; is a variable stored in RAM, initialized to 0 at startup (cstart), cached values may be used.是存储在 RAM 中的变量,在启动 (cstart) 时初始化为 0,可以使用缓存值。

const int temp; is a variable stored in (read-ony)FLASH, initialized to 0 at compiler time, cached values may be used.是存储在(只读)FLASH 中的变量,在编译器时初始化为 0,可以使用缓存值。

volatile int temp; is a variable stored in RAM, initialized to 0 at startup (cstart), cached values will NOT be used.是存储在 RAM 中的变量,在启动 (cstart) 时初始化为 0,不会使用缓存值。

const volatile int temp; is a variable stored in (read-ony)FLASH, initialized to 0 at compiler time, cached values will NOT be used是存储在(只读)FLASH 中的变量,在编译器时初始化为 0,不会使用缓存值

Here comes the usefull part:有用的部分来了:

Nowadays most Embedded processors have the ability to make changes to their read-only non-volatile memory by means of a special function module, in which case const int temp can be changed at runtime, altought not directly.如今,大多数嵌入式处理器都能够通过特殊功能模块对其只读非易失性存储器进行更改,在这种情况const int temp可以在运行时更改const int temp ,而不是直接更改。 Said in another way, a function may modify the value at the address where temp is stored.换句话说,函数可以修改存储temp的地址处的值。

A practical example would be to use temp for the device serial number.一个实际的例子是使用temp作为设备序列号。 The first time the embedded processor runs, temp will be equal to 0 (or the declared value) and a function can use this fact to run a test during production and if sucessfull, ask to be assigned a serial number and modify the value of temp by means of a special function.嵌入式处理器第一次运行时, temp将等于 0(或声明的值),一个函数可以使用这个事实在生产过程中运行测试,如果成功,要求分配一个序列号并修改temp的值通过特殊功能。 Some processors have a special address range with OTP (one-time programmable) memory just for that.一些处理器有一个特殊的地址范围,带有 OTP(一次性可编程)内存。

But here comes the difference:但不同之处在于:

If const int temp is a modifiable ID instead of a one-time-programmable serial number and is NOT declared volatile , a cached value might be used untill the next boot, meaning the new ID might not be valid untill the next reboot, or even worse, some functions might use the new value while other might use an older cached value untill reboot.如果const int temp是一个可修改的 ID 而不是一次性可编程的序列号,并且未声明为volatile ,则可能会使用缓存值直到下一次启动,这意味着新 ID 可能在下一次重新启动之前无效,甚至更糟糕的是,某些功能可能会使用新值,而其他功能可能会使用较旧的缓存值,直到重新启动。 If const int temp IS declared voltaile , the ID change will take effect immediately.如果const int temp IS 声明为voltaile ,则 ID 更改将立即生效。

You can use const and volatile together.您可以同时使用constvolatile For example, if 0x30 is assumed to be the value of a port that is changed by external conditions only, the following declaration would prevent any possibility of accidental side effects:例如,如果假定0x30是仅由外部条件更改的端口值,则以下声明将防止任何意外副作用的可能性:

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

This article discusses the scenarios where you want to combine const and volatile qualifiers.本文讨论了您想要组合 const 和 volatile 限定符的场景。

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

In simple terms, Value in 'const volatile' variable cannot be modified programmatically but can be modified by hardware.简单来说,'const volatile' 变量中的值不能以编程方式修改,但可以通过硬件修改。 Volatile here is to prevent any compiler optimisation. Volatile 是为了防止任何编译器优化。

We use 'const' keyword for a variable when we don't want to the program to change it.当我们不想让程序改变它时,我们对变量使用“const”关键字。 Whereas when we declare a variable 'const volatile' we are telling the program not to change it and the compiler that this variable can be changed unexpectedly from input coming from the outside world.而当我们声明一个变量“const volatile”时,我们是在告诉程序不要改变它,编译器可以从外部世界的输入中意外地改变这个变量。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM