访问易失性局部变量不是从 C++ 中函数外部可观察到的行为吗?

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

在 C++03 标准可观察行为 (1.9/6) 中包括读取和写入易失性数据。现在我有这个代码:

int main()
{
    const volatile int value = 0;
    if( value ) {
    }
    return 0;
}

它正式初始化一个易失性变量,然后读取它。 Visual C++ 10 发出机器代码,通过将双字压入堆栈来在堆栈上腾出空间,然后将零写入该堆栈位置,然后读取该位置。

对我来说,这是没有意义的 - 没有其他代码或硬件可能知道局部变量所在的位置(因为它位于自动存储中),因此期望该变量可以被任何其他方读取/写入是不合理的,所以这种情况可以消除。

是否允许消除此变量访问?访问任何其他方都不知道的易失本地地址是可观察行为吗?

c++ visual-c++ compiler-optimization volatile
6个回答
8
投票

线程的整个堆栈可能位于受保护的内存页上,并有一个处理程序记录所有读取和写入(当然,并允许它们完成)。

但是,我认为 MSVC 并不真正关心是否或如何检测内存访问。它理解

volatile
的意思是“不要费心对此对象应用优化”。所以事实并非如此。这不一定有意义,因为 MSVC 对加速这种
volatile
的使用不感兴趣。

由于是否以及如何实际观察到可观察行为取决于实现,因此我认为如果实现知道由于硬件细节而无法检测到访问,则它可以“欺骗”,这是正确的。没有物理可检测影响的可观察行为可以被跳过:无论标准如何规定,检测不合格行为的方法都仅限于物理上可能的情况。

如果在森林中实施不符合标准,并且没有人注意到,它会发出声音吗?类似这样的事情。


3
投票

这就是声明变量的全部意义

volatile
:您告诉实现该变量可能会更改或通过实现本身未知的方式读取,并且实现应该避免执行可能影响此类访问的优化。

当一个变量被声明为

volatile
const
时,你的程序可能不会改变它,但它仍然可以从外部改变。这意味着不仅变量本身,而且其上的所有读取操作都无法被优化。


2
投票

没有其他代码或硬件可能知道

您可以查看程序集(您刚刚做了!),找出变量的地址,然后在调用期间将其映射到某些硬件。

volatile
意味着实施也有义务考虑这些事情。


1
投票

Volatile 也适用于您自己的代码。

volatile int x;
spawn_thread(&x);
x = 0;
while (x == 0){};

如果

x
不是易失性的,这将是一个无限循环。

至于const。我不确定编译器是否可以用它来决定。


1
投票

对我来说这没有任何意义 - 没有其他代码或硬件可能 知道局部变量位于哪里(因为它是自动的 存储)

真的吗?因此,如果我编写一个 x86 模拟器并在其上运行您的代码,那么该模拟器将不知道该局部变量?

实现实际上可以永远不知道确定该行为是不可观察的。


0
投票

我的回答有点晚了。无论如何,这个声明

对我来说这没有任何意义 - 没有其他代码或硬件可能 知道局部变量位于哪里(因为它是自动的 存储)

是错误的。在VC++2010中,挥发性与非挥发性的区别实际上是非常明显的。例如,在发布版本中,您无法将断点添加到通过优化消除的局部变量声明中。因此,如果您需要为变量声明设置断点,或者只是为了在调试器中观察其值,我们必须使用调试构建。 要在发布版本中调试特定的局部变量,我们可以使用 volatile 关键字:

int _tmain(int argc, _TCHAR* argv[])
{
    int a; 
    //int volatile a;
    a=1; //break point here is not possible in Release build, unless volatile used

    printf("%d\n",a);
    return 0;
}
© www.soinside.com 2019 - 2024. All rights reserved.