bit*_*ask 9 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
Run Code Online (Sandbox Code Playgroud)
现在,我一直试图在标准中找到一个点,告诉我编译器在遇到这些语句时的行为方式.我能找到的只是A(可能是C)给我一个左值,B也是如此:
标识符是一个id表达式,只要它已被适当声明(第7条).[..]
[..]结果是由标识符表示的实体.如果实体是函数,变量或数据成员,则结果是左值,否则为prvalue.
[..]
一元*运算符执行间接:它所应用的表达式应该是指向对象类型的指针,或指向函数类型的指针,结果是指向表达式指向的对象或函数的左值.
我用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)
Run Code Online (Sandbox Code Playgroud)
G ++这是否有意的,因为如手册中所述(当是易失性C++对象访问?)的标准是不清楚什么构成volatile限定对象的访问.如上所述,您需要强制左值到右值转换以强制来自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.
Run Code Online (Sandbox Code Playgroud)
对于C++ 03,G ++行为和GCC手册似乎是正确的,但是相对于DR 1054引入的C++ 03,C++ 11有所不同(这也解释了为什么Clang在C++中表现不同)3和C++ 11模式).5 [EXPR] P10限定丢弃值表达,并表示,对于挥发的左值到右值转换被应用到ID-表达如您的语句A和C的规格为左值到右值转换(4.1 [conv.lval])表示结果是glvalue的值,它构成了volatile的访问.根据5p10,你的所有三个语句都应该被访问,因此需要更新G ++对语句C的处理以符合C++ 11.我已将其报告为http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59314
本gcc文档7.1 何时访问易失性 C++ 对象?与此相关,我引用(强调我的未来):
\n\nC++ 标准与 C 标准的不同之处在于对易失性对象的处理。它没有指定什么构成了易失性访问,只是说 C++ 在易失性方面应该以与 C 类似的方式运行。
\n在 void 上下文中访问对象时,C 和 C++ 语言规范有所不同:
\n
并提供了这个例子:
\nvolatile int *src = somevalue;\n*src;\nRun Code Online (Sandbox Code Playgroud)\n并继续说道:
\n\n\nC++ 标准指定此类表达式不会进行左值到右值的转换,并且取消引用的对象的类型可能不完整。C++ 标准没有明确指定左值到右值的转换是导致访问的原因。
\n
这应该指的是标准草案5.3.1 一元运算符第1段,其中说:
\n\n一元 * 运算符执行间接寻址:应用它的表达式应是指向对象类型的指针,或指向函数类型的指针,结果是引用表达式所指向的对象或函数的左值。[...]
\n
关于参考文献:
\n\n\n当使用对 易失性 的引用时,G++ 不会将等效表达式视为对易失性的访问,而是发出警告,表明没有访问易失性。这样做的理由是,否则很难确定易失性访问发生在哪里,并且不可能忽略返回易失性引用的函数的返回值。同样,如果您希望强制读取,请将引用强制转换为右值。
\n
所以它看起来像是gcc选择以不同的方式对待对 volatile 的引用,并且为了强制读取,您需要转换为rvalue,例如:
static_cast<volatile int>( c ) ;\nRun Code Online (Sandbox Code Playgroud)\n它生成纯右值,从而生成左值到右值的转换,来自5.2.9 静态转换部分:
\n\n表达式 static_cast(v) 的结果是将表达式 v 转换为类型 T 的结果。如果 T 是左值引用类型或函数类型的右值引用,则结果是左值;如果 T 是对象类型的右值引用,则结果是 xvalue;否则,结果是纯右值。
\n
更新
\nC ++11 标准草案添加了5 表达式第11段,其中表示:
\n\n在某些情况下,表达式仅因其副作用而出现。这样的表达式称为丢弃值表达式。计算表达式并丢弃其值。不应用数组到指针 (4.2) 和函数到指针 (4.3) 标准转换。当且仅当表达式是 volatile 限定类型的左值并且是以下其中一项时,才应用左值到右值转换 (4.1):
\n
包括:
\n\n\n\xe2\x80\x94 id 表达式 (5.1.1),
\n
这对我来说似乎模棱两可,因为关于a;和c;部分5.1.1 p8说它是一个lvalue,而且对我来说它并不明显它涵盖了这种情况,但正如乔纳森发现的那样,DR 1054说它确实涵盖了这种情况。
| 归档时间: |
|
| 查看次数: |
564 次 |
| 最近记录: |