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)处理。- 这些操作依赖于如何解释二进制数,
B2U
和B2T
可能会导致不同的值。 - 补码公式:负数的补码是先取反,然后加1。补码的存在目的是统一加减法操作,使得计算机能统一处理正负数。
-
补码、反码、原码的区别:
- 原码:最高位表示符号(0为正,1为负)。
- 反码:负数的反码是将原码的每一位取反。
- 补码:负数的补码是反码加1,具有方便计算的特点。
补码的意义:补码简化了加减法操作,正负数的加法可以统一处理,避免了特殊处理负数的情况。
5. 有符号与无符号数字(Unsigned & Signed Numeric Values)¶
同一二进制表示在有符号和无符号整数中表示的数值不同。例如:
- 对于
B2U
和B2T
,相同的二进制位在有符号数和无符号数下会映射成不同的值。
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)2147483948U:2147483948U 是无符号整数 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^w
(w
是类型的位数,如32位中的2^32
)进行调整:
通俗总结¶
- 位模式是“物理”的:转换时二进制位原封不动。
- 数值是“逻辑”的:根据类型规则重新计算数值。负数转无符号会“绕到”大正数,大无符号数转有符号会“绕到”负数,就像钟表超过12点会回到1点一样。
9. 负数不对称的原因¶
在计算机中,正负数的表示方式并不对称。0是中点,负数没有对应的正数,最高位被用来表示符号。
例如,TMIN(最小负数)没有对应的-TMIN,所以 if(x < 0) return -x;
可能会导致 TMIN
不会返回其对应的负数值,而是返回TMIN他本身
10. 左移的解释¶
左移操作将一个整数的二进制位向左移动,每次左移一位相当于将数字乘以2。
11. 三列表问题¶
三列表是指循环中判断的条件控制,例如在下面的循环中:
如果
i
是无符号整数,i >= 0
会始终为真,导致死循环。解决方法:将
i >= 0
改为 i - sizeof(char) >= 0
,这是因为 sizeof(char)
是无符号的。 12. 符号扩展(Sign Extension)¶
符号扩展是将一个 w 位的有符号整数扩展为更高位数的整数时,保持符号位不变。扩展的高位填充原来符号位的值。
13. 截断(Truncating)¶
截断是去掉超出部分的位,类似模运算。例如,保留低8位,可以通过模运算 x % (2^8)
来完成。