移位运算符对比 java和c 补码

7 篇文章 0 订阅
5 篇文章 0 订阅

移位运算符对比 java和c

自己尤其喜欢使用位运算符,不是为了装x,在做密码方面的工作时经常要用到位操作。早就想比较和总结一下Java和C的位运算的不同之处了,所以借这几天的空闲时间做一下比较。其实不同之处很少,但是想要讲明白需要讲解以下数值的存储方式。

以下结论均以实验为根据

一、二进制整数存储的方式

顺带提一下实际存储时整数(char, short, int, long)的存储方式。实际存储时是以二进制补码存储的,大家都知道正数的补码还是整数本身,负数补码是其 反码 + 1(反码是除符号位各位取反)。

那何谓补码,为啥要用补码,很多地方都可以看到,补码可以方便存储、方便减法的计算等,不详细介绍了。为了下面介绍方便,我们均使用 8 位整数(char,一个字节)来讲解(其余的只是长度不一样)。这里只能是顺带讲一下,如果要完全搞明白,只看我写的这点恐怕不够,其实并不难,就是得把弯绕过来。

先看无符号整数,8位应该称为无符号字符 unsigned char。

 [7] [6] [5] [4] [3] [2] [1] [0]

从右往左分别表示最低位到最高位,无符号即每一位都表示数字,没有符号的概念,那么可以表示的数的范围位 0 - 255,共256个数。而编程有符号整数时,需要拿出最高位作为符号位,但是可以表示的树的个数仍然是256个,只不过范围变成了 -128 - 127,相当于从数轴上往后平移了而已。

那么如何理解补码呢?

补码仅仅在有符号整数中有意义,我们称上面可以表示的数的个数(256 二进制为 1 0000 0000)为 “模数”。补码,顾名思义是补出来的,那么是拿什么补出来的呢? 大家回想一下中学学的补角,如果两个角之和是一个平角(180度),那么它俩互补。在这里,这个模数就类似平角,如果两个数之和为模数,那么它俩就互补。

举个例子,1111 1111,原码(所谓的原码就是人本来可以理解的)表示-127,其补数就是 1 0000 0000 - 1111 1111 = 0000 0001,其确定的就是负数的绝对值。负数永远是负数,所以其首位依然应该是1,那么 -127的补码应该是 1000 0001。而1000 0001原码表示为-1,其补码则为 1111 1111。为了方便计算,我们可以记住,补码就是其反码末位加一,而反码就是原码除符号位以外,其余各位取反(所谓的原码依然是一个中间概念)。

看一个特殊的例子,1000 0000,原码表示-0,1 0000 0000 - 1000 0000 = 1000 0000,我们发现用模数减完依然是这个数,在无符号中,其表示128。而在有符号是,1000 0000 和 0000 0000似乎都是表示0,那么就将 -0 表示为-128。其实这也是合理的(不仅仅是为了凑够256个数),1000 0000 + 1 = 1000 0001刚好就是我们上面所计算的 -127的反码,闭环了啊。

然而我们使用反码加一的方法计算1000 0000 的补码时,反码:1111 1111,末位加一则出现了溢出。

二、C/C++中的移位运算符

注意:C中存在signed int 和 unsigned int。

C中只有两个运算符,<< 左移,>> 右移。

但是大家又经常会听到逻辑右移算术右移的概念,其实这个是由于C中存在有符号和无符号的原因。

对于左移<<,无符号和有符号都是一样的,左移直接丢弃最高位,在最低位补0。那么有喜欢思考的同学要问了,假如是1000 0001,那么左移岂不是把1移走了,负数变成正数了吗?

回答这个问题前,请提问者先想清楚你这个1000 0001是-127还是 -1,上面的讲完了之后,我们就要以补码的来看待有符号整数了。想明白这个问题后,我回答你,确实是把负数-127变成了正数。左移操作本身相当于乘2操作,-127 * 2 = -254,已经溢出了,那么结果应该是2,就好比钟表的-10点,应该是2点一个意思。(这个地方还是牵扯到模的问题,不细讲还是挺难懂)。

对于右移>>,就分两种情况了,在无符号整数中,右移操作为,最低位丢弃最高位补0,也就是逻辑右移。例如

unsigned char n = 5;
n >>= 1;

结果为 n = 2。

对于有符号整数,最高位补0还是补1,根据其本来的符号决定,即整数补0,负数补1,也就是算术右移。例如

char n = 5;
n >>= 1;
char m = -5;
m >>= 1;

结果,n = 2, m = -3

有两个有趣的算术右移永远等于其本身,-1和0。

三、Java中的移位运算操作

注意:Java中本身没有无符号的数值。

所以,Java中定义了3个移位运算符,<< 左移, >> 右移 和 >>> 无符号右移。
上面的看懂了,下面的就显而易见了。

左移操作和C语言中一样,丢弃最高位,在最低位补0

右移操作相当于C语言中的算术右移。

无符号右移相当于C语言中的逻辑右移(但是又不相同,只是操作相同,因为C语言中逻辑右移是用于无符号数值中的),最高位补0

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值