const 和 const 之间的区别常量易失性

发布于 2024-10-10 09:41:28 字数 181 浏览 3 评论 0原文

如果每次更新新值时我们都将变量声明为易失性
如果我们将变量声明为 const 那么该变量的值将不会改变

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

If we declare a variable as volatile every time the fresh value is updated
If we declare a variable as const then the value of that variable will not be changed

Then const volatile int temp;
What is the use of declaring the variable temp as above?
What happens if we declare as const int temp?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

清君侧 2024-10-17 09:41:28

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

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

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

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

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

一个简单的例子:

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

如果这些指针没有被标记为易失性,则可能会出现几个问题:

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

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

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.

The volatile part of the qualifier means that the compiler cannot optimize or reorder access to the object.

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.

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:

  • 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). 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.
  • 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.

The volatile qualifiers ensures that these optimizations are not performed by the compiler.

情何以堪。 2024-10-17 09:41:28
  • 易失性会告诉编译器不要优化与变量相关的代码,通常是当我们知道它可以从“外部”(例如另一个线程)更改时。
  • const会告诉编译器禁止程序修改变量的值。
  • const volatile 是一个非常特殊的东西,你可能会在你的生活中看到它被使用了 0 次(tm)。正如所料,这意味着程序无法修改变量的值,但可以从外部修改该值,因此不会对变量执行优化。
  • volatile will tell the compiler not to optimise code related the variable, usually when we know it can be changed from "outside", e.g. by another thread.
  • const will tell the compiler that it is forbidden for the program to modify the variable's value.
  • const volatile is a very special thing you'll probably see used exactly 0 times in your life (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.
北陌 2024-10-17 09:41:28

这并不是因为该变量是 const,所以它在两个序列点之间可能没有改变。

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

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.

夏日浅笑〃 2024-10-17 09:41:28

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

基本上,const 意味着该值不能由程序修改。

易失性意味着该值会突然发生变化(可能来自程序外部)。

事实上,C 标准给出了一个有效声明的示例,该声明既是 const 又是 volatile。示例为:

extern const volatile int real_time_clock;

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

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

In C, const and volatile are type qualifiers and these two are independent.

Basically, const means that the value isn’t modifiable by the program.

And volatile means that the value is subject to sudden change (possibly from outside the program).

In fact, the C Standard gives an example of a valid declaration which is both const and 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.

So we should already treat const and volatile separately. These type qualifiers can be applied to struct, union, enum and typedef as well.

暖伴 2024-10-17 09:41:28

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

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

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

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...

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 has to be const volatile.

装纯掩盖桑 2024-10-17 09:41:28

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

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

You can use const and volatile together. 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:

const volatile char *port = (const volatile char *)0x30;
森林迷了鹿 2024-10-17 09:41:28

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

易失性意味着变量可能随时改变,因此不能使用缓存的值;对变量的每次访问都必须执行到其内存地址。

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

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

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

因此:

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

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

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

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

这里是有用的部分:

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

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

但区别在于:

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

const means that the variable cannot be modified by the c code, not that it cannot change. 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; 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:

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.

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.

In consequence:

int temp;is a variable stored in RAM, initialized to 0 at startup (cstart), cached values may be used.

const int temp;is a variable stored in (read-ony)FLASH, initialized to 0 at compiler time, cached values may be used.

volatile int temp; is a variable stored in RAM, initialized to 0 at startup (cstart), cached values will NOT be used.

const volatile int temp; is a variable stored in (read-ony)FLASH, initialized to 0 at compiler time, cached values will NOT be used

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. Said in another way, a function may modify the value at the address where temp is stored.

A practical example would be to use temp for the device serial number. 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. Some processors have a special address range with OTP (one-time programmable) memory just for that.

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.
If const int temp IS declared voltaile, the ID change will take effect immediately.

层林尽染 2024-10-17 09:41:28

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

In simple terms,
Value in 'const volatile' variable cannot be modified programmatically but can be modified by hardware. Volatile here is to prevent any compiler optimisation.

心凉 2024-10-17 09:41:28

当我们不希望程序更改变量时,我们对变量使用“const”关键字。然而,当我们声明变量“const volatile”时,我们是在告诉程序不要更改它,并且告诉编译器该变量可能会因来自外部世界的输入而被意外更改。

We use 'const' keyword for a variable when we don't want to the program to change it. 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文