Skip to content

coding_005

Zhang Jc edited this page Nov 28, 2018 · 2 revisions

C中的整数编码

1. 负数用补码表示

C等编程语言中一般用补码表示有符号数。补码的意思就是计算时最高位权值为负。比如对于一个4字节的int,1000 0000 0000 0000 为最小的数,其绝对值为 2^31,表示-2^31。 最大的数为0111 1111 1111 1111为2^31 - 1。

2. 类型转换

位数扩展

对于无符号数,扩展的高位补0,这明显不会改变数的大小。

对于有符号数,扩展的高位全部填充原始的符号位。这也不会改变数的大小:对于正数很好理解,符号位为0,和无符号数一样没有影响;对于负数,虽然新扩展的位全部为1,经过推算数的大小也是不变的。

位数缩减

对于位数的缩减的情况,则直接截断前边的若干位,这也相当于做了取模运算,这种可能导致这个数的大小发生改变,这也是溢出的一种情况。

3. 隐式转换

  • 若一个有符号数和一个无符号数进行运算,有符号的会被隐式地转为无符号的再进行预算。

  • 两个不同类型数进行预算,位数小的会被隐式转为位数最大的数的类型。

  • 赋值运算时,右值最终结果会被转为左值类型再付给左值。

4. 溢出

乘法或加法、有符号或者无符号数都可能溢出,运算后相当于将值作截断处理,所以可能不是预期的结果。

加法:

  • 对于无符号数,很显然,两个最大的正数相加后的结果需要多一位才能进行存储,所以肯定会导致溢出。

  • 对于有符号数,由于补码的特性,其运算的机器指令和无符号数相同,但是由于第一位为符号位,产生正数变负数,负数变正数的溢出:

    • 当两个较大正数相加时,符号位会被置1;
    • 当两个绝对值较大负数相加时,符号位会被置0;

乘法:

乘法和加法类似,也是算完后截取,也是有符号和无符号的机器指令相同,也有可能发生溢出情况。


[1] CSAPP chapter. 2

Clone this wiki locally