3

我试图了解积分提升如何与算术移位运算符一起工作。特别是,我想知道,哪些值a, b, c, d, e, f, g, h是根据 C++14 标准精确定义的,哪些值可以依赖于平台/硬件/编译器(假设sizeof(int) == 4)。

int a = true << 3;
int b = true >> 3;

int c = true << 3U;
int d = true >> 3U;

int e = true << 31;
int f = true >> 31;

int g = true << 31U;
int h = true >> 31U;
4

2 回答 2

2

来自 [expr.shift]:

结果的类型是提升的左操作数的类型。如果右操作数为负数,或者大于或等于提升的左操作数的位长度,则行为未定义。

移位 a 的结果类型bool总是int,不管右手边是什么。我们永远不会改变至少 32 或负数,所以我们在所有方面都很好。

对于左移(E1 << E2):

否则,如果 E1 具有带符号类型和非负值,并且 E1×2 E2可以在结果类型的相应无符号类型中表示,则转换为结果类型的那个值就是结果值;否则,行为未定义。

1×2 31可以用 表示unsigned int,这是我们正在做的最大的左移,所以我们在所有情况下都可以。

对于右移(E1 >> E2):

如果 E1 具有带符号类型和负值,则结果值是实现定义的。

E1 永远不会是负数,所以我们也可以!任何地方都没有未定义或实现定义的行为。

于 2015-10-13T18:58:30.560 回答
0

以下主要是对巴里答案的补充,清楚地解释了左右移动的规则。

至少对于 C++11,bool 的积分提升为 0false和 1 true:4.5 积分提升 [conv.prom] § 6

bool 类型的纯右值可以转换为 int 类型的纯右值,其中 false 变为 0,而 true 变为 1。

因此,在原始示例中bdfh都将得到一个 0 值,a并且c都得到一个8值:直到这里只有完美定义的行为。

但是eandg会收到 unsigned value 0x80000000,所以如果你将它影响到一个 unsigned int 变量就可以了,但是你使用的是有符号的 32 位整数。所以你得到一个积分转换:4.7 积分转换 [conv.integral] §3

如果目标类型是有符号的,则如果它可以在目标类型中表示,则值不变;否则,该值是实现定义的。

并且无符号 0x80000000 不能用带符号的 64 位整数表示,因此结果是为和定义的实现eg

于 2015-10-13T20:53:50.303 回答