为什么指向“易失性”的指针(例如“ volatile int * p”)有用?


77

volatile告诉编译器不要优化引用,以便每次读/写操作都不会使用寄存器中存储的值,而是进行真正的内存访问。我可以理解它对于某些普通变量很有用,但不了解它如何volatile影响指针。

volatile int *p = some_addr;
int a = *p; // CPU always has to load the address, then does a memory access anyway, right?

如果声明为,有什么区别int *p = some_addr

Answers:


140

形式的指针

volatile int* p;

是指向的指针int,编译器将其视为volatile。这意味着编译器将假定p所指向的变量可能已更改,即使源代码中没有任何内容暗示可能发生这种情况。例如,如果我设置p为指向正整数,则每次读写时*p编译器都知道该值可能已意外更改。

还有一种用例volatile int*:如果声明一个intas volatile,则不应以常规指向它int*。例如,这是一个坏主意:

volatile int myVolatileInt;
int* ptr = &myVolatileInt; // Bad idea!

这样做的原因是C编译器不再记住由指向的变量ptris volatile,因此它可能会*p错误地在寄存器中缓存值。实际上,在C ++中,以上代码是错误的。相反,您应该写

volatile int myVolatileInt;
volatile int* ptr = &myVolatileInt; // Much better!

现在,编译器会记住ptr指向a的位置volatile int,因此它不会(或不应该!)尝试通过优化访问*ptr

最后一个细节-您讨论的指针是的指针volatile int。您也可以这样做:

int* volatile ptr;

这表示指针本身volatile,这意味着编译器不应尝试将指针缓存在内存中或尝试优化指针值,因为指针本身可能会被其他东西(硬件等)重新分配。如果你想得到这只野兽,那就在一起:

volatile int* volatile ptr;

这表示指针和指针都可能会意外更改。编译器无法优化指针本身,也无法优化所指向的内容。

希望这可以帮助!


我认为您的意思是“您不应该使用常规的int *指向它”
markgz 2012年

1
我认为这也是C语言中的错误,但是C编译器不太容易抱怨类型不匹配。
克里斯·卢茨

谢谢。因此,对于我的示例而言,是否存在“易失性”也没什么区别,对吗?但是如果后面还有另一个statemenet“ int b = * p”,那确实有所作为,对吗?具体而言,可以使用存储“ * p”的寄存器而不是进行实存储器引用来初始化“ b”。
2012年

1
@ SetTimer-这实际上取决于什么do_something_else。如果可以完全确信编译器do_something_else从未更改过的值x,那么如果需要的话,它肯定可以*p从寄存器中读取值。我怀疑对于任何合理的代码和大多数编译器而言,这种情况实际上是否会发生,但是从理论上讲,这种可能性是否可能。那有意义吗?
templatetypedef

1
C11版本1.10的@olaf缺陷报告摘要日期:2016年4月DR 476左值的易变语义04/2016开放
philipxy

9

此代码volatile int *p = some_addr声明一个指向的指针volatile int。指针本身不是volatile

在极少数情况下,您需要指针和int都是易变的,则需要使用:

volatile int * volatile p;

我想不出需要使用它的情况。


4
示例:我在ISR代码中使用了'volatile uint8_t * volatile pData',用于修改指针及其指向的数据。指针由主代码设置,指针和数据都在以后读取。
Christoph

2

关于volatile的有用性:如果需要检查内存(这是由硬件(如串行接口控制器)修改的),则需要这样做。它在嵌入式系统的世界中都有其应用,您可以在非常接近硬件的情况下工作,而无需任何操作系统。


1
或者,如果您正在开发操作系统。
Atilla Filiz
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.