【问题标题】:Is accessing volatile local variables not accessed from outside the function observable behavior in C++?是否在 C++ 中访问未从函数可观察行为外部访问的 volatile 局部变量?
【发布时间】:2011-11-25 01:33:15
【问题描述】:

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

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

正式初始化一个 volatile 变量,然后读取它。 Visual C++ 10 发出机器代码,通过将 dword 压入栈中腾出空间,然后将零写入该栈位置,然后读取该位置。

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

是否允许消除此变量访问?访问一个 volatile local 的地址对于任何其他方可观察的行为都不知道?

【问题讨论】:

    标签: c++ visual-c++ compiler-construction volatile compiler-optimization


    【解决方案1】:

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

    但是,我认为 MSVC 并不真正关心是否或如何检测到内存访问。它理解volatile 的意思是“不要费心对这个对象应用优化”。所以它没有。这不一定有意义,因为 MSVC 对加速这种volatile 的使用不感兴趣。

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

    如果一个实现在森林中不符合标准,而没有人注意到,它会发出声音吗?那种东西。

    【讨论】:

      【解决方案2】:

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

      当一个变量同时声明volatileconst 时,你的程序可能不会改变它,但它仍然可以从外部改变。这意味着不仅变量本身,而且对它的所有读取操作都不能被优化掉。

      【讨论】:

      • const volatile 的含义很简单:这意味着变量不能在我的代码中更改(我不能++ 那个变量),但可以由第三方更改。
      【解决方案3】:

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

      您可以查看程序集(您刚刚做了!),找出变量的地址,并在调用期间将其映射到某些硬件。 volatile 表示实现也有义务考虑这些事情。

      【讨论】:

        【解决方案4】:

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

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

        如果 x 不是 volatile,这将是一个无限循环。

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

        【讨论】:

        • @sharptooth Plus 编译器通常不会决定副作用。主要是因为这是一个复杂的领域。
        • 如果是(&x),我会同意——在大多数非易失性变量的情况下,这也会抑制消除。
        • @sharptooth 已编辑。抱歉,我一开始就是这个意思。
        • volatile 和同步无关。如果spawn_thread 修改x,您将拥有UB。
        【解决方案5】:

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

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

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

        【讨论】:

        • 好吧,程序会使用push ecx 为该变量腾出空间。模拟器如何知道它是为此目的而不仅仅是为了保留ecx
        • FWIW,我认为实际的编译器对于 volatile 读取可能有点不可靠。因此,如果模拟器(或对程序集的检查)在实践中会发现问题,例如volatile int a = 0; (void)a; (void)(a+a);,我不会感到惊讶
        【解决方案6】:

        我的回答有点晚了。反正这个说法

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

        错了。 volatile 与否之间的区别实际上在 VC++2010 中非常明显。例如,在 Release 构建中,您不能在已被优化消除的局部变量声明中添加断点。因此,如果您需要为变量声明设置断点,甚至只是为了在 Debugger 中查看其值,我们必须使用 Debug 构建。要在 Release 构建中调试特定的局部变量,我们可以使用 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;
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-04-15
          • 2011-01-25
          • 1970-01-01
          • 2017-05-25
          • 2013-04-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多