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

发布于 2024-12-06 06:31:47 字数 405 浏览 1 评论 0原文

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

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

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

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

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

In C++03 Standard observable behavior (1.9/6) includes reading and writing volatile data. Now I have this code:

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

which formally initializes a volatile variable and then reads it. Visual C++ 10 emits machine code that makes room on the stack by pushing a dword there, then writes zero into that stack location, then reads that location.

To me it makes no sense - no other code or hardware could possibly know where the local variable is located (since it's in automatic storage) and so it's unreasonable to expect that the variable could have been read/written by any other party and so it can be eliminated in this case.

Is eliminating this variable access allowed? Is accessing a volatile local which address is not known to any other party observable behavior?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

南…巷孤猫 2024-12-13 06:31:47

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

但是,我认为 MSVC 并不真正关心是否或如何检测内存访问。它理解 易失性 的意思之一是“不必费心对此对象应用优化”。所以事实并非如此。它不一定有意义,因为 MSVC 对加速 易失性 的这种使用不感兴趣。

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

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

The thread's entire stack might be located on a protected memory page, with a handler that logs all reads and writes (and allows them to complete, of course).

However, I don't think MSVC really cares whether or how the memory access might be detected. It understands volatile to mean, among other things, "do not bother applying optimizations to this object". So it doesn't. It doesn't have to make sense, because MSVC is not interested in speeding up this kind of use of volatile.

Since it's implementation-dependent whether and how observable behavior can actually be observed, I think you're right that an implementation can "cheat" if it knows, because of details of the hardware, that the access cannot possibly be detected. Observable behavior that has no physically-detectable effect can be skipped: no matter what the standard says, the means to detect non-conforming behavior are limited to what's physically possible.

If an implementation fails to conform to the standard in a forest, and nobody notices, does it make a sound? Kind of thing.

可是我不能没有你 2024-12-13 06:31:47

这就是声明变量易失性的全部意义:您告诉实现该变量可能会更改或通过实现本身未知的方式读取,并且实现应该避免执行可能影响此类访问的优化。

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

That's the whole point of declaring a variable volatile: you tell the implementation that that variable may change or be read by means unknown to the implementation itself and that the implementation should refrain from performing optimizations that might impact such access.

When a variable is declared both volatile and const your program may not change it, but it may still be changed from outside. This implies that not only the variable itself but also all read operations on it cannot be optimized away.

自由如风 2024-12-13 06:31:47

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

您可以查看程序集(您刚刚做了!),找出变量的地址,然后在调用期间将其映射到某个硬件。 易失性意味着实现也有义务考虑这些事情。

no other code or hardware could possibly know

You can look a the assembly (you just did!), figure out the address of the variable, and map it to some hardware for the duration of the call. volatile means the implementation is obliged to account for such things too.

凡尘雨 2024-12-13 06:31:47

易失性也适用于您自己的代码。

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

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

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

Volatile also applies to your own code.

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

This will be an endless loop if x is not volatile.

As for the const. I'm unsure whether the compiler can use that to decide.

深爱成瘾 2024-12-13 06:31:47

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

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

实现实际上永远无法知道该行为是不可观察的。

To me it makes no sense - no other code or hardware could possibly
know where the local variable is located (since it's in automatic
storage)

Really? So if I write an x86 emulator and run your code on it, then that emulator won't know about that local variable?

The implementation can never actually know for sure that the behaviour is unobservable.

苏辞 2024-12-13 06:31:47

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

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

是错误的。在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;
}

My answer is a bit late. Anyway, this statement

To me it makes no sense - no other code or hardware could possibly
know where the local variable is located (since it's in automatic
storage)

is wrong. The difference between volatile or not is actually very observable in VC++2010. For instance, in Release build, you cannot add a break point to a local variable declaration that was eliminated by optimization. Hence, if you need to set a break point to a variable declaration or even just to watch its value in the Debugger, we have to use Debug build. To debug a specific local variable in Release build, we could make use of the volatile keyword:

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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文