纠正涉及具有可变变量的表达式的琐碎语句的行为
Correct behaviour of trivial statements involving expressions with volatile variables?
考虑以下语句
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一元运算符"
一元*运算符执行间接操作:应用它的表达式应是指向对象类型的指针,或指向函数类型的指针。结果是指向表达式所指向的对象或函数的左值。
clang和gcc
我在clang++3.2-11和g++4.7.3中尝试了这一点,第一个在C++11模式下产生了三次读取,在C++03模式下产生零次读取(输出三次警告),而g++只产生了前两次,明确警告我不会产生第三次。
问题
很清楚哪种类型的值来自表达式,来自标准中引用的行,但是:
根据C++标准,哪个语句(A、B、C)应该从易失性实体产生读取
关于"隐式取消引用"的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++有意这样做,因为正如手册中所述(何时访问易失性C++对象?),该标准不清楚什么是对易失性限定对象的访问。如前所述,您需要强制进行左值到右值的转换,以强制从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.
G++行为和GCC手册似乎对C++03是正确的,但与DR 1054引入的C++03相比,C++11存在差异(这也解释了为什么Clang在C++)3和C++11模式中表现不同)。5[expr]p10定义了一个丢弃值表达式,并表示对于volatile,左值到右值的转换应用于id表达式
此gcc
文档7.1何时访问易失性C++对象?与此相关,我引用(强调我的未来):
C++标准与C标准在处理挥发性物质方面有所不同它没有指定什么构成易失性访问,只是说C++在易失性方面的行为应该与C类似
当在void上下文中访问对象时,C和C++语言规范不同:
并提供了这个例子:
volatile int *src = somevalue;
*src;
并继续说道:
C++标准规定这样的表达式不进行左值到右值的转换,并且去引用对象的类型可能是不完整的。C++标准没有明确指定导致访问的是左值到右值的转换。
应参考标准草案5.3.1
一元运算符第1段,其中写道:
一元*运算符执行间接操作:应用它的表达式应该是指向对象类型的指针,或者是指向函数类型的指针。结果是引用表达式所指向的对象或函数的左值。[…]
关于参考文献:
当使用对volatile的引用时,G++不会将等效表达式视为对volatiles的访问,而是发出警告,表示没有访问volatile。这样做的理由是,否则很难确定易失性访问发生在哪里,也不可能忽略返回易失性引用的函数的返回值。同样,如果您希望强制读取,请将引用强制转换为右值。
因此,看起来gcc
选择以不同的方式处理对volatile的引用,并且为了强制读取,您需要转换为右值,例如:
static_cast<volatile int>( c ) ;
它从5.2.9
静态转换部分生成prvalue,从而生成lvalue-to-rvalue转换:
表达式static_cast(v)的结果是将表达式v转换为类型T的结果。如果T是左值引用类型或对函数类型的右值引用,则结果为左值;如果T是对对象类型的右值引用,则结果为x值否则,结果为prvalue
更新
C++11标准草案增加了5
表达式第11段,其中写道:
在某些情况下,表达式只会因其副作用而出现。这样的表达式称为丢弃值表达式。将计算表达式,并丢弃其值。数组到指针(4.2)和函数到指针(4.3)的标准转换不适用应用左值到右值的转换(4.1),当且仅当表达式是volatile限定类型的左值,并且它是以下值之一:
包括:
--id表达(5.1.1),
这对我来说似乎很模糊,因为关于a;
和c;
,5.1.1 p8
节说它是lvalue
,我不清楚它涵盖了这个案例,但正如Jonathan发现的,DR 1054说它确实涵盖了这个案件。
- 优化/减少 if 语句中的条件表达式
- 为什么这个复合语句作为用大括号和括号括起来的语句序列似乎不是有效的语句表达式
- "()"如何在C++中将语句转换为表达式?
- 代码样式:在 switch/if 语句的分支中重用控件表达式或控制变量
- 如果语句表达式调用函数,则需要测试是否为 true
- C++如果使用 lambda 表达式的语句返回 true,但输出来自 false,为什么
- if 语句中的复合表达式
- 重构模板函数中的常量表达式 if 语句
- 在 if 语句中返回布尔值的 lambda 表达式
- 理解 while 语句中的逻辑表达式
- 为什么我不能在我的三元表达式中使用 return,但我可以在常规的 if-else 语句中使用?
- IF-ELSE语句的Lambda表达式的返回类型扣除
- 不是完整表达式的语句
- 如何在 lambda 表达式C++中使用 goto 语句
- C++ 中的正则表达式语句未按预期工作
- 带有 or 表达式的 If 语句中的语法错误
- 为什么C 开关语句仅限于恒定表达式
- ranged-for 语句中的表达式是否在每次迭代时计算
- C#指针:错误CS0254:固定语句赋值的右侧可能不是强制转换表达式
- 复制 ELISION:在 return 语句中使用三元表达式时未调用移动构造函数