整数的二进制底层表示
对于字长(word size)为w的机器,用w位bit表示一个字(word)。
无符号整数的二进制表示
如果该字表示一个无符号整数的话,我们可以用下列公式来计算
范围 : 0<=x<2w−1
有符号整数的二进制表示
如果该字表示一个有符号整数的话,现代计算机通常使用补码(two’s complement)方式的编码方式。
补码的确定规则基于这样的事实:
对于一个正整数x,它的相反数y,那么 x+y=0 是符合我们的直觉的。
对于 [xw−1,xw−2.....x0] 例如 x=0000001 想找另外的一个 [yw−1,yw−2.....y0] y使得 x+y=0000000 (如果 bitlen(x+y)==w+1 截断最高位)那么 y=1111111 推导出 y= x+1
因为 x=0000001 表示正整数的1,为了使得 y=1111111 表示-1,我们采用以下公式 :
我们给了最高位一个很大的负权重来达到我们的目的。
范围 : −2w−1<=x<=2w−1−1
这种编码方式成为补码。
使用 <stdints.h>
和<inttype.h>
由于不同机器的字长(字长影响数据范围)不同,c语言在不同字长的机器上int
的大小可能略有区别,考虑到可移植性,我们应该尽量使用c99标准库的<stdints.h
和<inttype.h>
中的类型。
int main(void)
{
int16_t x0 = 10;
int32_t x1 = 10000;
int64_t x2 = 1000000000000;
printf("x0 : %d\n",x0);
printf("x1 : %d\n",x1);
printf("x2 : %" PRId64 "\n", x2);
return 0;
}
需要注意的是输出int64_t
的时候使用PRId64
这是<inttype.h>
中的一个宏。
有符号整数和无符号整数之间的转换
c语言中一旦操作符某一边出现了unsigned int
那么都会被自动转换为unsigned int
这种转换是隐式的不宜察觉,很多bug由此出现。应当了解具体的细节。
转换的时候,bit sequence是不会改变的,只是编译器对它的解释方式发生变化。
有符号->无符号
看一个例子 :
int x = -50;//signed
unsigned y = 1;
if(x > y)
printf("ok\n");
程序输出为ok
,这是因为if(x > y)
这条语句,x是signed,y是unsigned,x会自动cast为unsiged,根据上边的公式可知,cast后必定大于1,所以会输出ok
无符号->有符号
看一个例子 :
unsigned x = (1 << 31);
int y = x;
printf("x = %ud , y = %d\n",x,y);
x = 2147483648d , y = -2147483648
套用上述公式即可解释
整数二进制表示形式的扩展和截断
不同字节的整数转换是一种常见的操作。
无符号整数的扩展
对于w字长的无符号整数 [xw−1,xw−2