指向 易失性的 C 指针在有下标时是否将寻址内存视为易失性内存?

问题描述 投票:0回答:3

考虑这两个定义:

volatile int a[10];
volatile int *p = a; 

编辑:澄清问题。

如果我们引用

a[3]
,内存位置将被视为
volatile
存储,也就是说,编译器不会假设它保持不变。

对于数组,很明显其意图是将数组的整个内容视为

volatile

在 C 中,

p[3]
也指代
volatile
存储吗,尽管
p
被声明为指针,而不是数组?换句话说,在使用“指向
volatile
的指针”的表达式中,例如
p[3]
*(p + 3)
volatile
“传染性”,并且它是否适用于除 所指向的确切位置之外的内存位置指向
volatile

的指针

我确实知道编译器将内存视为易失性意味着什么。

c volatile
3个回答
2
投票

在C中是不是p[3]也指易失性存储...

是的,

volatile int *p
使
p
成为指向 volatile int 的指针。因此,使用
p
(又名
p
的取消引用)进行的任何访问都将被视为对易失性内存的访问。

请注意,

p
本身不是易失性的。只有
p
所指向的才是不稳定的。

这并不是一个证明,但为了好玩,您可以尝试从

p
中删除“易失性”,例如:

volatile int a[10];
int *p = a;

用例如编译这个

gcc
会向您发出如下警告:

warning: initialization discards 'volatile' qualifier from pointer target type [-Wdiscarded-qualifiers]

这很清楚地表明出了问题,因为

p
不再指向 volatile int。

顺便说一句: 常量指针与指向常量的指针可能会是一本有趣的读物。是关于

const
而不是
volatile
但原理是一样的。


0
投票

我不确定为什么每个人都在谈论“易失性存储”,好像它意味着一些特殊的东西。

volatile
只是 C 语言中的一个关键字,告诉编译器不要对变量做出任何假设,永远不要优化它,并且总是在使用它之前从内存中重新加载它。就是这样。最常见的用法是与硬件相关的编程:内存映射硬件寄存器、DMA 缓冲区等。

要指向声明为

volatile
的变量,指针还必须具有代码中的
volatile
限定符。当限定符
volatile
const
等)放置在指针声明中
*
的左侧时,它指的是指向的数据。因此:

volatile* int x; // pointer to volatile data
int* volatile y; // volatile pointer to non-volatile data

“抛弃”限定符通常是未定义的行为。另外,赋值规则规定,对于

x = y
x
必须至少具有
y
的所有限定符,但不一定是相反的方式。

对于数组,在大多数表达式中使用时,它们会“衰减”为指向第一个元素的指针。而“decay”得到的指针带有数组项的所有限定符。因此,在您的情况下,当在大多数表达式中使用时,

a
将变成
volatile int*

每当通过

volatile
限定指针访问对象时,都适用与直接访问对象时相同的规则。

(到目前为止,C 标准中存在一个小问题,最终将在即将推出的 C23 中得到修复。到目前为止,C 标准已经谈到对声明的易失性对象的访问算作副作用。在 C23 中,此问题已修复为包括所有易失性限定类型的左值访问。)


-3
投票

与流行的看法相反,声明

volatile int
不会产生任何易失性存储,它只是告诉编译器将其视为如此。

volatile
不适用于 x86 以外的多线程问题,因为其他处理器的内存模型较弱,并且编译器不会发出必要的指令。
volatile
只告诉编译器不要优化变量访问,不要发出内存屏障。

将会发生的情况是,对

a
的任何访问或通过
p
无论其指向何处的任何访问都不会被优化掉。就是这样,不多也不少。

实际的易失性存储器是这样声明的:

extern volatile int trisa;
并且定义是由无法用标准c编写的目标文件提供的。
volatile
for 内存映射 IO。它还有其他目的,但这就是它被创建的原因。当
setjmp()
中的规范引用
volatile
时,它知道编译器不知道的东西;
setjmp()
会破坏调用保留的寄存器,因此将本地变量视为易失性内存可以正常工作。

© www.soinside.com 2019 - 2024. All rights reserved.