为什么ACCESS_ONCE如此复杂?

8
Linux的ACCESS_ONCE宏定义如下:
#define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))

我了解这段代码的作用,但不明白为什么它如此复杂?我的理解是它完成以下操作:

  1. 获取关注变量的地址(创建一个临时指针)
  2. 将其转换为相同类型的volatile指针
  3. 对该指针进行解引用操作

你有什么想法,为什么不能以更简单的方式实现,比如:

 #define ACCESS_ONCE(x) ((volatile typeof(x))(x))
2个回答

13
ACCESS_ONCE宏用于从存储位置检索值,该存储位置已知(或被怀疑)为易变的,但未被标记为此类类型。目的是以这样的方式检索存储位置的当前值,以打败优化编译器,否则可能会将值缓存到寄存器中,或者根本不提供存储位置。按照C标准,通过声明适当类型的指向该位置的指针,可以间接地将“volatile”应用于存储位置。这要求严格按照抽象机器的规则评估对象。你提出的修改不会将“volatile”应用于存储位置,因此无法实现此目的。检索值的操作可能会受到优化。顺便说一下,我认为这是所述目的的简洁模型。对于比这更糟糕的事情,我保留“复杂”的说法。

谢谢你,David,提供清晰明确的解释。 - user3480510
一些更多的背景信息:C标准允许将“volatile”限定符分配给数据,而不是对数据的访问。有很多人认为这很愚蠢;其中包括Linus在内。此外,“volatile”还存在一些问题,以至于在Linux内核、多线程等方面被视为有害。因此,在ACCESS_ONCE宏(和类似宏)中使用的技术是一种在需要时仅强制执行具有C volatile语义的访问的方法,避免了缺点。请注意,这引起了足够的争议,以致于导致GCC回归! - hmijail

0

对于“简单”变量进行volatile转换基本上是无用的 - 它不会改变底层访问语义,因此这不是您想要的。


你怎么知道他/她想要什么? - jag
1
如果你将任何东西转换为volatile,你可能会期望将该任何东西的存储类更改为volatile。然而,它并不是这样工作的。把一个强制类型转换想象成创建一个临时对象,该对象具有所需的类型(如果你将整数转换为double,你不会期望底层变量变为double,对吧?)。 - mfro

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接