C ++ 20是否为“溢出”的有符号整数很好地定义了左移?

时间:2019-04-02 07:06:18

标签: c++ language-lawyer bit-shift c++20

在当前的C ++标准草案中,左移运算符的定义如下[expr.shift]

  

E1 << E2的值是唯一值,与E1×2^E22^N相等,其中N是该类型的宽度结果。

请考虑具有32位的int E1 = 2^31-1 = 2'147'483'647E2 = 1int。然后,有无数个与E1×2^E2 = 4'294'967'294模为2^N = 2^32的数相等的数字,即4'294'967'294 + k×2^32,其中k是任意整数。例如4'294'967'294k=0)或-2k=-1)。

我不理解这些数字中的唯一值意味着标准的含义。它表示可以用结果数据类型表示的唯一值吗?然后,我假设结果定义为-2。这种解释正确吗?

直到C ++ 20,定义都不同,这种情况将导致未定义的行为。我想这个变化与负号整数的强制性2's补码表示有关。

事实上,现在不再需要E2为非负数。因此,似乎-1 << 1被定义为-2。那也对吗?

2 个答案:

答案 0 :(得分:5)

  

是否表示可以由结果表示的唯一值   数据类型

是的。与E1×2^E22^N相等的一组数字是无限的,但是在大小为2^N的任何间隔中只有一个值,因此在宽度的整数类型中只有一个可表示的值N

如果我们查看"p0907R1 Signed Integers are Two’s Complement" proposal,我们会发现一个类似的短语,带有“唯一表示”,这使它更加清晰:

  

从有符号到无符号的转换始终是明确定义的:结果   是目标类型的唯一值 ,与   源整数模2 N

  

然后,我想将结果定义为-2。这是解释吗   对吗?

在x64上,等效的asm指令为shlx(逻辑左移)

  

我认为更改与强制性2补语有关   负整数的表示形式。

正确。就像无符号类型一样,现在它们也用数学方式表示等效类(嗯,对我来说这还不算是多少,因为看起来他们仍然想让一些UB实例保持溢出状态)。

答案 1 :(得分:2)

所以我们知道:

E1 = 2147483647
E2 = 1
N = sizeof(int) * CHAR_BIT = 4 * 8 = 32

让我们计算E1×2^E2 modulo 2^Nmodulo是除法的余数):

x = E1×2^E2 mod 2^N = 2147483647 * 2 ^ 1 mod 4294967296 = 4294967294 mod 4294967296 = 4294967294

然后我们转到here

  

对于有符号整数类型的每个值x,   对应于x模2 N的对应无符号整数类型具有   其值表示形式中对应位的值相同。

我认为我们也需要:

  

有符号整数类型的值的以2为基的表示形式是   以2为基的相应值的等值表示   无符号整数类型。

这意味着x = 4294967294的{​​{1}}等于x = -2。因此结果将是signed int

  

因此,似乎将-1 << 1定义为-2。也是吗?

-2