C++ 包含可变变量表达式的平凡语句的正确行为?

C++ 包含可变变量表达式的平凡语句的正确行为?,c++,standards,volatile,language-lawyer,C++,Standards,Volatile,Language Lawyer,考虑以下陈述 volatile int a = 7; a; // statement A volatile int* b = &a; *b; // statement B volatile int& c = a; c; // statement C 现在,我一直试图在标准中找到一点,告诉我遇到这些语句时编译器的行为。我所能找到的就是A(可能还有C)给了我一个左值,B也一样: “§5.1.1.8主要表达-概述”如 标识符是一个id表达式,前提是它已被适当声明(第7条)。

考虑以下陈述

volatile int a = 7;
a;   // statement A
volatile int* b = &a;
*b;  // statement B
volatile int& c = a;
c;   // statement C
现在,我一直试图在标准中找到一点,告诉我遇到这些语句时编译器的行为。我所能找到的就是A(可能还有C)给了我一个左值,B也一样:

“§5.1.1.8主要表达-概述”如 标识符是一个id表达式,前提是它已被适当声明(第7条)。[…]
[…]结果是由标识符表示的实体。结果是一场灾难 如果实体是函数、变量或数据成员且为 否则为prvalue。
[……]

“§5.3.1一元运算符”表示 一元*运算符执行间接寻址:应用它的表达式应为指向对象类型的指针,或指向函数类型的指针,结果为引用表达式所指向的对象或函数的左值

叮当声与gcc 我在clang++3.2-11和g++4.7.3中尝试了这一点,第一个在C++11模式下产生了三次读取,在C++03模式下产生了零次读取(输出三次警告),而g++只产生了前两次,明确警告我第三次将不会生成

问题: 很明显,哪种类型的值来自于表达式,来自于标准中引用的行,但是:

哪个语句(A,B,C)应该根据C++标准从易失性实体产生读?

< P> >这里代码> GCC < /Cord>文档是相关的,我引用(强调我的前进):

< > C++标准与C标准在处理挥发性物质方面不同。强>它不能指定什么构成了一个易失性访问<强>,除了说C++应该以类似于C的方式对挥发物

进行行为。

当在空格上下文中访问对象时,C和C++语言规范不同:

并提供了以下示例:

volatile int *src = somevalue;
*src;
并继续说:

C++标准指定这样的表达式不接受LValt到RValo转换,并且被删除对象的类型可能不完整。C++标准没有明确指定它是导致访问的rValueReals/.p> 应参考标准草案第5.3.1节一元运算符第1段,其中规定:

一元*运算符执行间接寻址:应用它的表达式应为指向对象类型的指针,或指向函数类型的指针,结果为引用表达式所指向的对象或函数的左值。[……]

关于参考文献:

当使用对volatile的引用时,G++不会将等效表达式视为对volatile的访问,而是发出警告,表示未访问volatile。这样做的基本原理是,否则很难确定易失性访问发生在何处,也不可能忽略返回易失性引用的函数的返回值。同样,如果要强制读取,请将引用强制转换为右值

因此,
gcc
似乎选择以不同的方式处理对volatile的引用,为了强制读取,您需要强制转换为右值,例如:

static_cast<volatile int>( c ) ;
static_cast(c);
从第
5.2.9节
Static cast生成一个prvalue,并由此生成一个从左值到右值的转换:

表达式static_cast(v)的结果是将表达式v转换为类型T的结果。如果T是左值引用类型或函数类型的右值引用,则结果是左值;如果T是对对象类型的右值引用,则结果是一个x值否则,结果为prvalue。

更新

第11段增加了
5
表达式,其中规定:

在某些上下文中,表达式仅因其副作用而出现。这样的表达式称为丢弃值表达式。表达式将被求值,其值将被丢弃。数组到指针(4.2)和函数到指针(4.3)的标准转换不适用当且仅当表达式是volatile限定类型的左值且是以下类型之一时,才会应用左值到右值的转换(4.1):

包括:

-id表达式(5.1.1)

这对我来说似乎模棱两可,因为关于
a
c章节
5.1.1第8页
说它是一个
左值
,我不清楚它是否涵盖了这个案例,但正如Jonathan发现的那样,它确实涵盖了这个案例。

关于“隐式解引用”的G++警告来自
gcc/cp/cvt.c
中的代码,该代码故意不通过引用加载值:

    /* Don't load the value if this is an implicit dereference, or if
       the type needs to be handled by ctors/dtors.  */
    else if (is_volatile && is_reference)
G++故意这样做,因为正如手册()中所述,标准不清楚什么构成对易失性限定对象的访问。如上所述,您需要强制进行左值到右值的转换,以强制从volatile加载

Clang在C++03模式下发出警告,表示类似的解释:

a.cc:4:3: warning: expression result unused; assign into a variable to force a volatile load [-Wunused-volatile-lvalue]
  a;   // statement A
  ^
a.cc:6:3: warning: expression result unused; assign into a variable to force a volatile load [-Wunused-volatile-lvalue]
  *b;  // statement B
  ^~
a.cc:8:3: warning: expression result unused; assign into a variable to force a volatile load [-Wunused-volatile-lvalue]
  c;   // statement C
  ^
3 warnings generated.

对于C++03来说,G++行为和GCC手册似乎是正确的,但是C++11与C++03之间存在差异,这是由(这也解释了为什么Clang在C++3和C++11模式中的行为不同)引入的。5[expr]p10定义了一个废弃值表达式,并表示对于volatile,左值到右值的转换应用于id表达式,如语句a和C。左值到右值的转换规范(4.1[conv.lval])表示结果是glvalue的值,它构成了volatile的访问。根据5p10,所有三条语句都应该是access,因此G++对语句C的处理需要更新以符合C++11。我将其报告为

我很难理解这与标准是否需要从