关于记录的可接受性和正确性有几个问题,例如--x++
说什么
(--x)++是等价的是否正确(x-1)?也就是说,这段代码是否正确并且不会产生未定义的行为?为什么必须在减量周围加上括号?我预计如果没有括号,构造中的编译器
--x++将首先采用前缀操作,然后是后缀操作,但由于某种原因,它会做相反的事情:error: lvalue required as decrement operand cout << --x++ << endl; ^~这个编译器行为正确吗?
程序示例:https ://ideone.com/q0Wu6U
#include <iostream>
using namespace std;
int main()
{
int x = 8;
cout << (--x)++ << endl;
cout << x << endl;
return 0;
}
根据定义,表达式的
(--x)++行为类似于(x = x - 1)++. 从 C++17 开始,赋值运算符的求值过程是非常严格的:右侧完全排在左侧之前,赋值行为本身排在赋值结果求值之前操作员。即
a = bC++ 17中计算赋值运算符的过程被划分为相互隔离的“隔间”[[a] = [b]],从右到左处理首先,评估值
b并在b然后计算该值
a并在a然后进行实际分配。
并且只有在这之后,表达式的结果才会
a = b返回到更高级别的上下文中这意味着不存在
(--x)++未定义行为的情况。所有副作用和值读取都严格相对于彼此排序。该表达式不改变 的值x,其结果是原始值x减去1。在 C++14 及更早版本中,情况可能会有所不同……例如,在 C++17 之前,一个表达式会
i = i++产生未定义的行为,但从 C++17 开始,该表达式的行为已经完全定义。但是,在您的具体示例中,C++11 中的一切都很好。形式上,行为在 C++98 中没有定义,但即使这样也被认为是 C++98 标准中的缺陷。值得注意的是,尽管 C++17 在评估单个赋值运算符的过程中引入了相当严格的顺序,但上述“隔间”并不能保证评估多个独立赋值运算符的过程彼此隔离。该表达式
(i = 1) + (i = 2)仍然会产生未定义的行为,因为副作用i = 1相对于副作用没有排序i = 2。在 C 和 C++ 中,无论年龄大小,后缀运算符都优先于前缀运算符。所以我不清楚你为什么期望什么
--x++可能是一个有效的表达。看到 operator后,
--编译器需要一个对象,并且由于它x++返回一个临时对象,因此该操作变得无效。有了括号,这个问题就消失了:先是减少对象的值,然后对同一个对象执行算子++关于第一个问题:我没有看到任何不正确的地方,也没有理由出现未定义的行为...... PS 此类表达式中的未定义行为是
--x + x--由于标准没有定义计算操作数的顺序(什么先评估--x还是x--?)在问题的情况下,这个问题没有。会有未定义的行为,你在同一个序列点有两个变化。括号不会创建一个点。
1) 操作优先级: http://cppstudio.com/post/302/ 先后缀,后前缀。2) 后缀自增返回对临时对象(右值)的引用,而前缀自减只接受对永久对象(左值)的引用。3) 这里没有什么可以产生未定义的行为。--x 返回左值(对 x 的引用),(--x)++ 返回右值 - ((--x) 的副本)+ 1。右值对象的输出操作有效。此外,如果启用优化,它将直接用 x-1 替换此代码:
gcc9.1 -O2
https://godbolt.org/z/rq1uA-