整数的内存表示---记录一道题目
最近面试,面试官问我的竟然都是程序员宝典里面的C++问题,这里记录一下看程序员宝典过程中遇到的问题,当做一种日记吧。整数无非是负数,正数和0,他们在内存中的二进制表示和原码、反码、补码息息相关。
一、原码、反码、补码的定义
1.原码
正数的原码的符号位为0,负数的原码符号位为1,其他位则表示为是其绝对值的二进制形式。记录几个例子:
X=+1011011 [X]原码=01011011
Y=-1011011 [Y]原码=11011011
[+1]原码=00000001 [-1]原码=10000001
[+127]原码=01111111 [-127]原码=11111111
例如对于-127要求其原码,首先由于它是负数所以符号位是1,然后其绝对值为127所对应的二进制是1111111,所以-127的原码是11111111。
原码表示的整数范围是:-(2n-1-1)~+(2n-1-1),其中n为机器字长。则:8位二进制原码表示的整数范围是-127~+127。16位二进制原码表示的整数范围是-32767~+32767。
2.反码
对于一个带符号的数来说,正数的反码与其原码相同,负数的反码为其原码除符号位以外的各位按位取反。记录例子,当机器字长为8位二进制数时:
X=+1011011 [X]原码=01011011 [X]反码=01011011
Y=-1011011 [Y]原码=11011011 [Y]反码=10100100
[+1]反码=00000001 [-1]反码=11111110
[+127]反码=01111111 [-127]反码=10000000
反码表示的整数范围与原码相同。
3.补码
正数的补码与其原码相同,负数的补码为其反码在最低位加1。记录几个例子:
(1) X=+1011011 (2) Y=-1011011
(1) 根据定义有: [X]原码=01011011 [X]补码=01011011
(2) 根据定义有: [Y]原码=11011011 [Y]反码=10100100 [Y]补码=10100101
补码表示的整数范围是-2n-1~+(2n-1-1),其中n为机器字长。则:8位二进制补码表示的整数范围是-128~+127(-128 表示为10000000,无对应的原码和反码)。16位二进制补码表示的整数范围是-32768~+32767。当运算结果超出这个范围时,就不能正确表示数了,此时称为溢出。
最后记录一下程序员宝典上的这道题目:
有两个变量a和b,不用if,?:,switch或者其他判断语句,找出两个数中比较大的。
其中有一个方案是:
int c = a - b; char *strs[2] = {"a Large", "b Large"}; c = unsigned(c) >> (sizeof(int) * 8 - 1);
这里的思路就是计算a-b,然后判断c的符号位是0还是1。是0就代表a大。由于c是有符号整型这时候要右移31位获得符号位,如果此时c是负数那么右移之后左边补的是1,所以最终c的取值不在是0,1。所以需要将c转为无符号整型,这样右移之后左边补的是0,最终c保存的就是1~31位是0,第0位保存的是符号位,所以c的取值要不是0,要不是1。