是否正确转移cpp和java中负数的未定义行为?

时间:2017-08-01 05:45:10

标签: java c++ undefined-behavior c++17

为了优化我的cpp代码,我尝试在某些情况下使用Right Shifting。这是一个例子:

int main()
{
    int i = (1 - 2) >> 31;  // sizeof(int) == 4
    ...
    ...
}

我打印了i,我得到-1。这意味着如果数字为负数,它将使用1代替0来填充空位置。换句话说,-1 >> 31的工作原理如下:

1111...1    <--- the result of (1 - 2), which is -1
1111...1    <--- -1 >> 31, 1 is used to fill in the empty position

我只是想知道这种行为是否已明确定义?

如果在cpp中是UB,在Java中怎么样?

3 个答案:

答案 0 :(得分:1)

即可。它是实现定义的。

根据 C ++ 03 5.8 / 3 定义右移:

  

E1&gt;&gt;的值E2是E1右移E2位位置。如果E1有   无符号类型或E1具有带符号类型和非负值,   结果的值是E1商的不可分割的一部分   除以数量2提升到功率E2。 如果E1已签名   类型和负值,结果值是   实现定义

有关详细信息,请参阅此link

答案 1 :(得分:1)

默认情况下,它是signed int。范围是-32767到32767,位位范围-111111111111111到+111111111111111左边的第一位充当负或正指示。并且所有算术运算都将以2的补码方法完成。通常,负int表示两个补码方法,即以-1为例表示-1。

4 Bytes = 32 bits
0000 0000 0000 0000 0000 0000 0000 0000
how represent 1
0000 0000 0000 0000 0000 0000 0000 0001
Then we invert the digits. 0 becomes 1, 1 becomes 0.
1111 1111 1111 1111 1111 1111 1111 1110
Then we add 1.
1111 1111 1111 1111 1111 1111 1111 1111
This is how -1 is represented

负数的右移定义为以1s移位到最高位位置,然后在2s补码表示中它将表现为算术移位 - 右移N的结果将与除以2N,向负无穷大四舍五入。所以-1的移位是-1 现在拿另一个号码 例如, 如果你有8位2s补码二进制数,则表示-3

    0000 0011
    Then we invert the digits.
    1111 1100
    Then we add 1. 
    1111 1101

11111101以十进制表示-3,并且您执行算术右移1,得到11111110,表示小数为-2,这与-3除以2 ^ 1相同,给出-1.5向负无穷大舍入在-2。

答案 2 :(得分:0)

Java 中,对于负数,>>的行为定义明确(见下文)。

C ++ 中,对于负数,>>的行为未定义(请参阅answer by rsp)。

引用Java语言规范,§15.19. Shift Operators

  

n &gt;&gt; s 的值为 n 右移 s 位位置使用符号扩展。结果值为 floor(n / 2 s 。对于 n 的非负值,这相当于将整数除法(由整数除法运算符/计算)截断2,除以幂 s

     

n &gt;&gt;&gt; s 的值为 n 右移 s 位位置零扩展,其中:

     
      
  • 如果 n 为正,则结果与 n&gt;&gt;的结果相同小号

  •   
  • 如果 n 为负且左侧操作数的类型为int,则结果等于表达式(n&gt; &gt; s)+(2 <&lt;〜-s)

  •   
  • 如果 n 为负且左侧操作数的类型为long,则结果等于表达式(n&gt; &gt; s)+(2L&lt;&lt; ~s)

  •