Skip to content

Bits, Bytes, and Integer

约 913 个字 3 行代码 预计阅读时间 5 分钟 共被读过

1. 64位机器的含义

当说“64位机器”时,指的是该计算机的地址总线宽度为64位,也就是说它的内存地址是64位长。换句话说,计算机可以寻址的内存空间最多为 2^[64]个地址。


2. 位运算集合理解

位操作是对整数的二进制位进行直接操作。比如:

  • 与(AND):两个二进制位都为1时结果才为1。
  • 或(OR):两个二进制位只要有一个为1结果就为1。
  • 非(NOT):将二进制位反转(1变0,0变1)。
  • 异或(XOR):两个二进制位相同则结果为0,不同则结果为1。

集合理解就是将这些操作看作集合运算,比如:

  • AND 就像集合的交集
  • OR 就像集合的并集
  • XOR 就像集合的对称差(不同的元素集合)

3. 位移操作(Shift operations)

  • 左移 (<<):数字左移相当于乘以 2 的某次方。移位的位数即为该次数。例如 x << 8,意味着将x的值乘以 2^8。

  • 算术移位与逻辑移位

    • 逻辑移位:不管符号位,直接移位。
    • 算术移位:移位时保持符号位不变,适用于带符号数。

    区别:算术移位保留符号,而逻辑移位不考虑符号。

    对于 x << 8 为什么是 x * 256(而不是 0),原因是位移操作并不改变原值,而是将该值左移,填补零。它是乘以2的8次方,即256。


4. 数字范围和整数编码(Numeric Ranges)

  • 编码整数(B2U 和 B2T)

    • B2U(X):将 X 作为无符号数(Unsigned)处理。
    • B2T(X):将 X 作为有符号数(Signed)处理。
    • 这些操作依赖于如何解释二进制数,B2UB2T 可能会导致不同的值。
    • 补码公式:负数的补码是先取反,然后加1。补码的存在目的是统一加减法操作,使得计算机能统一处理正负数。
  • 补码、反码、原码的区别

    • 原码:最高位表示符号(0为正,1为负)。
    • 反码:负数的反码是将原码的每一位取反。
    • 补码:负数的补码是反码加1,具有方便计算的特点。

    补码的意义:补码简化了加减法操作,正负数的加法可以统一处理,避免了特殊处理负数的情况。


5. 有符号与无符号数字(Unsigned & Signed Numeric Values)

同一二进制表示在有符号和无符号整数中表示的数值不同。例如:

  • 对于 B2UB2T,相同的二进制位在有符号数和无符号数下会映射成不同的值。

6. 有符号与无符号之间的映射(T2U & U2T)

  • T2U:将有符号整数转换为无符号整数,通常会改变数值。
  • U2T:将无符号整数转换为有符号整数,也会导致数值的变化。

7. 类型转换中的惊讶(Casting Surprises)

  • 比较过程中的类型转换
    • 如果在一个表达式中同时有有符号和无符号数,则有符号数会隐式转换为无符号数。

例如:

constant1 constant2 Relation Evaluation
2147483947 -2147483947 - 1 > signed
2147483947U -2147483947 - 1 < unsigned
(unsigned)-1 -2 > unsigned
2147483947 2147483948U < unsigned
2147483947 (int)2147483948U > signed

这些比较过程中,2147483947U-2147483947-1 的比较会因为类型不同而发生变化,而 (int) 是强制类型转换,用于将无符号整数转换为有符号整数。

2147483947 (int)2147483948U > signed
- 2147483947:这是一个有符号整数,值为 2147483947
- (int)2147483948U2147483948U 是无符号整数 2147483948,将其强制转换为有符号整数时,会将其二进制表示作为有符号数处理。由于 2147483948 大于 2^31(即 2147483648),转换为有符号数时会变成负数。
实际上,2147483948U 转换为 int 时,会得到一个负数,因为二进制补码表示超出了有符号整数的最大值范围。转换后的结果为 -2147483648
- 比较过程
- 2147483947 是正数,而 -2147483648 是负数,因此显然,2147483947 大于 -2147483648
- 所以,比较结果是 >
- 最后一列:signed 表示两者是在有符号数的上下文中进行比较的。
---

8. 强制类型转换的基本规则(Casting Signed <-> Unsigned)

1. 位模式保持

  • 二进制位不变:转换时,数据的二进制表示(位模式)完全保留,不会发生任何改变。例如,int32_t类型的-1(二进制为0xFFFFFFFF)强制转换为uint32_t后,二进制仍为0xFFFFFFFF
  • 解释方式改变:同样的二进制位模式,会根据类型(有符号或无符号)被重新解释。例如:
    • 有符号的0xFFFFFFFF(32位)表示-1(补码规则)。
    • 无符号的0xFFFFFFFF则表示4294967295

2. 数值的重新计算

转换后的数值可能通过加减2^ww是类型的位数,如32位中的2^32)进行调整:

通俗总结

  • 位模式是“物理”的:转换时二进制位原封不动。
  • 数值是“逻辑”的:根据类型规则重新计算数值。负数转无符号会“绕到”大正数,大无符号数转有符号会“绕到”负数,就像钟表超过12点会回到1点一样。

9. 负数不对称的原因

在计算机中,正负数的表示方式并不对称。0是中点,负数没有对应的正数,最高位被用来表示符号。

例如,TMIN(最小负数)没有对应的-TMIN,所以 if(x < 0) return -x; 可能会导致 TMIN 不会返回其对应的负数值,而是返回TMIN他本身


10. 左移的解释

左移操作将一个整数的二进制位向左移动,每次左移一位相当于将数字乘以2。


11. 三列表问题

三列表是指循环中判断的条件控制,例如在下面的循环中:

C
for (i = 8; i >= 0; i--){     
    // something 
}

如果 i 是无符号整数,i >= 0 会始终为真,导致死循环。
解决方法:将 i >= 0 改为 i - sizeof(char) >= 0,这是因为 sizeof(char) 是无符号的。

12. 符号扩展(Sign Extension)

符号扩展是将一个 w 位的有符号整数扩展为更高位数的整数时,保持符号位不变。扩展的高位填充原来符号位的值。


13. 截断(Truncating)

截断是去掉超出部分的位,类似模运算。例如,保留低8位,可以通过模运算 x % (2^8) 来完成。