【问题标题】:When would you need a volatile pointer?什么时候需要 volatile 指针?
【发布时间】:2014-05-03 20:37:59
【问题描述】:

我了解您何时需要指向易失性值的指针(例如,读取内存映射的外围设备)。但是你什么时候需要指针本身是可变的?>

【问题讨论】:

  • 同理,内容(即地址)可能会在当前源代码之外发生变化。 C 可以在可能发生这种情况的各种设备上使用。
  • 您能否详细说明“指针本身易变”的意思?请记住,volatile char *p 将p 声明为指向volatile char 的指针。您是否在询问类似:char *volatile p; 声明 p 是指向 char 的 volatile 指针?如果是这样,出于同样的原因,任何变量都可能成为volatile。
  • unsigned char* volatile ptr; // 指针本身是可变的
  • Paul,有什么具体的例子可以说明这种情况会发生在哪里?我的背景是嵌入式系统。
  • 没错,就是这样。答案仍然存在:出于同样的原因,任何其他变量都可能被声明为volatile。想象一下,例如,某些硬件将指向函数的指针存储在内存中某个已知的固定位置,并每 74 毫秒更新一次。

标签: c volatile


【解决方案1】:

为了稍微详细说明我的评论,重要的是首先要记住volatile 的含义:这是向编译器发出的一个信号,即声明的变量可以通过编译器无法看到或控制的机制以意想不到的方式发生变化并且读取和写入可能会产生副作用。因此,编译器通常会每次从主内存重新加载变量的值,而不是使用缓存的值,并且不会执行删除、重新排序或省略对此类volatile 变量的读取或写入的优化。

通常这种事情是大多数用户空间代码不必担心的事情,并且volatile 的合法使用很少见。

您的问题还提到了该语言的一个微妙且不为人知的特性:将 指针 本身声明为 volatile(或 const)而不是它指向的东西的能力.您可以使用以下语法:

int *volatile p = 0x74;

这声明了一个volatile 指针,该指针指向内存位置0x74 的int。对比一下:

volatile int *p = 0x74;

在地址0x74处声明一个指向volatile int的指针

这两者之间的区别在于当您访问p 时会发生什么。我们只关心阅读案例:

对于每次读取访问时指向volatile int 的指针,编译器将转到内存位置0x74 并读取(可能使用特殊的CPU 指令)该位置的int 值 - 该值不会是由 code 缓存(但可能由硬件缓存)。

对于指向int 的volatile 指针,编译器将在每次访问时重新加载指针的值,然后在该地址读取int。该地址不会被缓存在代码中(但同样,它可能会被硬件缓存)。

写入也是如此。

再次,请务必记住 volatile 会限制编译器(例如,它无法优化写入或读取),因为对 volatile 变量的任何操作都可能具有对编译器不可见的副作用编译器。这种副作用的一个例子可能是产生中断、使 LED 闪烁、写入审计记录或更改寄存器的值。

【讨论】:

  • volatile 不仅仅是编译器缓存访问。请参阅this example:如果没有volatile,如果优化程度足够高,编译器可以删除第一次写入,因为它会立即被覆盖。如果foo_register 指向一个内存映射寄存器,该寄存器需要特定的写入序列,这可能会产生灾难性的影响。 (根据硬件,您可能还需要障碍来停止重新排序。)
  • 对,我还没写完,过早地点击“发帖”。
  • volatile 不会阻止调用的重新排序,为此需要在每个调用之间设置内存屏障。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-12-26
  • 1970-01-01
  • 2012-09-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-17
相关资源
最近更新 更多