签名类型的按位移位运算符

我试图理解有符号运算符在有符号和无符号类型上的行为。 根据ISO / IEC文件,以下是我的理解。

左移算子

  • E1 << E2的结果是E1左移E2位位置

  • 左移帐户中的空位将由零填充。

  • E1为有符号非负数: E1 << E2将导致E1乘以E2的2次幂,如果该值可由结果类型表示。

  • Q1:签署否定书怎么样?

  • Q2:我无法理解以下语境中“减少模数”的含义。 “如果E1具有无符号类型,则结果的值为E1×2E2,比结果类型中可表示的最大值减少一个模数”

右移算子

  • E1 >> E2的结果是E1右移E2位的位置。

  • E1为有符号非负/无符号 :结果的值是E1 / 2E2的商的整数部分

  • Q3:对于有符号的负整数,我看到,有些书定义了空位将填充1详细说明使用右移运算符对带符号的负int。

Q1:左移位运算符对有符号整数类型的负值的行为是未定义的,当结果E1 * 2^E2在类型中无法表示时,有符号整数类型的正值的行为也是如此。

标准(n1570草案)第6.5.7节第4和第5段明确提到:

4 E1 << E2的结果是E1左移E2位位置; 腾出的位用零填充。 如果E1具有无符号类型,则结果的值为E1 × 2^E2 ,比结果类型中可表示的最大值减少一个模数。 如果E1具有有符号类型和非负值, 并且在结果类型中可以表示E1 × 2^E2 ,那么这就是结果值; 否则,行为未定义。

Q2:以无符号整数类型中可表示的最大值为模的减少模数意味着简单地丢弃在左侧移出的位。

在数学上,如果无符号类型的最大值是2^n - 1 (并且它始终是那种forms),则将E1向左移位的结果是在0到2^n - 1范围内的值V这样的区别

 (E1 * 2^E2 - V) 

可以被2^n整除,也就是说,它是将E1 * 2^E2除以2^n时得到的余数。

问题3:转换有符号整数类型的右负值时的行为是实现定义的。 最常见的行为(至少在两个补码机器上)是算术移位,也就是说,结果是向下舍入(朝向负无穷大)。

5 E1 >> E2的结果是E1右移E2位的位置。 如果E1具有无符号类型或者E1具有有符号类型和非负值,则结果的值是E1 / 2^E2的商的整数部分。 如果E1具有带符号类型和负值,则结果值是实现定义的。

  • 回复:Q1
    如果E1为负数,则行为未定义。

  • 回复:Q2
    无符号算术是“循环的”,也就是说,它是环绕的,因此UINT_MAX + 1再次为0 。 就好像每个计算都是以模UINT_MAX + 1完成的。 考虑它的另一种方法是简单地删除左边不适合的多余位。

  • 回复:Q3
    如果E1为负数,则结果为实现定义。 也就是说,它取决于你的机器/编译器/选项,但必须在某处记录(“定义”)行为,通常是编译器手册。 两种流行的选择是用左(1)算术移位或0(逻辑移位)填充左边的输入位。

如果你真的想了解按位移位运算符。 看看这些简单的规则:

1)在左移,E1 << E2,右侧的所有空位都将用零填充,如果数字是有符号或无符号无关紧要,则总是将零移入。

2)在左移,E1 >> E2,左侧的所有空位,如果数为正,则为0;如果数为负,则为1。请记住,无符号数从不为负数。 一些实现也可能在某些机器上用0填充,即使数字是负数,所以永远不要依赖于此。

所有其他场景可以通过这两个简单的规则来解释。 现在,如果你想知道移位后结果的值,只需写出数字的位表示并在纸上手动移位,并使用这两个规则在空位处输入位。 然后你就能更好地理解位移的工作原理。

 For example lets take int i = 7; i<<2 now i = 0000 0000 0000 0000 0000 0000 0000 0111 perform two left shits according to rule 1 would be: 0000 0000 0000 0000 0000 0000 0001 1100 

它将给出28的值(E1 * 2E2 = 7 * 2 * 2 = 28),这与位模式表示的相同。

现在让我解释“减少模数”的事情,如果你移动一个大数字,那么左边的位将丢失,“减少模数”补偿它,所以如果你的结果值如果大于最大值数据类型可以保持,左边的位将丢失,然后:result =(E1 * 2 * E2)%(maximumValue + 1)。

对于其他各种情况,请记住以上规则,你很好:)

Q2:“降值模数X”在数学中表示“值mod X”,可以在C中写为“value%X”。这部分只是解释了整数溢出是如何工作的。