带有增量的 2 的补码是否违反了 c++17 中的执行规则顺序,但不违反 c++14 中的执行规则?

问题描述 投票:0回答:1

这可能是“101”级别的问题,但有一些相关的痛苦,所以我会要求评论以保持自信。

我有一些遗留代码支持返回到 以及之前的这一行:

iTmp = ~iTmp++;

这 100% 有效,直到代码更改为 。更改为 后,它会计算出不同的值,但并非总是如此。这取决于该行在代码中的位置,是先执行 2 的补码还是先执行增量。

此外,如果您尝试强制使用括号,则会出现编译器错误:

iTmp = (~iTmp)++;

error C2105: '++' needs l-value

这对我来说很有意义,因为 2 的补码结果不是中间变量,因此 ++ 没有任何操作。

我的研究告诉我

  1. 这是“”失败。
  2. 不涉及,因为两个运算符都是二进制的。
  3. 二进制补码不是就地操作,因此它不会更改 iTmp,而是返回一个值。
  4. 遗留代码靠运气工作 - 可能是由于编译器错误或错误总是强制执行运算符评估顺序。

我的评价正确吗?

对我来说,一个非常微妙的区别是前面的代码无效,但这一行是可以的:

if ( ++iTmp > 0)

我没想到升级到 会导致这个微妙的错误,但我不得不将代码更改为以下内容来解决问题:

iTmp = ~iTmp;
iTmp++;
c++ c++17 c++14 operator-precedence order-of-execution
1个回答
1
投票

在代码更改为 c++17 之前,此方法 100% 有效。

在 C+17 之前它具有未定义的行为,因为

iTmp
有两个副作用(一个递增,一个分配),并且
=
和后递增都没有暗示这两个副作用之间的任何顺序。

看来你很幸运,编译器总是以你想要的方式编译它。

更改为 c++17 后,它会计算出不同的值,但并非总是如此。

不,从 C++17 开始,它被明确定义:首先完全评估赋值的右侧,即

iTmp
首先递增。然而,
iTmp++
产生
iTmp
的先前值,并且该值计算也在赋值的副作用之前排序。因此,它的行为与
iTmp = ~iTmp
等效,只是如果
iTmp
有符号并且按增量溢出,它还将具有 UB。

细化表达式求值顺序 惯用的 C++

这取决于该行在代码中的位置,是先执行 2 的补码还是先执行增量。

我不知道你的意思。编译器不再有选择。只有一个订单是正确的。

此外,如果您尝试强制使用括号,则会出现编译器错误:

是的,因为您无法增加右值(由

~
运算符生成)。

这对我来说很有意义,因为 2 的补码结果不是中间变量,因此 ++ 没有任何操作。

C++ 中不存在术语“立即变量”。原因是该表达式不是左值。这只是语言规范的某种任意选择。

这是“执行顺序”失败。

是的。

运算符优先级不参与其中,因为两个运算符都是二元的。

运算符优先级是相关的,因为您需要能够解析

~iTmp++
~(iTmp++)
,而不是
(~iTmp)++
。请注意,这只是关于解析。它不影响评估顺序。我不知道为什么您认为二元运算符在某种程度上并不意味着运算符优先级的相关性。

二进制补码不是就地操作,因此它不会更改 iTmp,而是返回一个值。

二进制补码”是一组位中带符号整数值的表示选择。运算符

~
只是 补码,整数类型的表示选择是什么并不重要。另外,是的,
~
不会修改
iTmp

遗留代码靠运气工作 - 可能是由于编译器错误或错误总是强制执行运算符评估顺序。

是的,这靠运气。但编译器根本不应该受到责备。代码根本就是错误的。

对我来说,一个非常微妙的区别是前面的代码无效,但这一行是可以的:

该行中仅对

iTmp
进行了一项修改。了解和理解 C++ 中求值规则的顺序以及它们何时导致未定义的行为(例如如果两个副作用或一个副作用和值计算未排序。

我没想到升级到 c++17 会导致这个微妙的错误,但我不得不将代码更改为以下内容来解决问题:

是的,这很好,并且不违反应遵循的一般规则:在每个表达式中最多修改每个对象一次。

© www.soinside.com 2019 - 2024. All rights reserved.