|
|
你这个问题问得非常好,很多初学者都会在这里有疑惑。关键在于你忽略了一个重要的前提:**int 类型变量的位数**。
你的想法 “234转化为二级制不就是11101010” 是正确的,但这只是234这个数值本身的有效位。在计算机中,一个变量(比如 int a)占据的内存空间是固定的,而不是根据数值大小变化。
在C语言中(尤其是在32位系统或大多数现代编译器中),一个 int 通常是 **32位(4字节)** 的。所以,当我们说 `a=234` 时,它在内存中的完整表示是:
- 00000000 00000000 00000000 11101010
- (高位) <------------------------> (低位)
复制代码
前面的24位都是0,只有最后8位是你看到的 `11101010`。
**~(按位取反)操作符是针对这个变量所有的32位进行操作的**,而不仅仅是最后8位。
所以,对完整的32位表示取反:
- 原码: 00000000 00000000 00000000 11101010
- 取反: 11111111 11111111 11111111 00010101
复制代码
得到的结果正是 `11111111 11111111 11111111 00010101`。
**为什么是 -235 ?**
这个结果在内存中就是上面那一串1和0。当我们用 `%d` (有符号十进制整数)打印它时,计算机会把这串二进制**解释为一个有符号数**。
* 最高位(最左边)是1,所以它是一个**负数**。
* 在计算机中,负数是用 **补码** 存储的。要得到它的绝对值(正数),需要对补码 “取反加1”。
* 对 `11111111 11111111 11111111 00010101` 进行 “取反加1”:
* 取反:`00000000 00000000 00000000 11101010` (这正是234!)
* 加1:`00000000 00000000 00000000 11101011` (这就是235)
* 所以,原来的补码表示的数就是 **-235**。
**为什么是 ffffff15 ?**
当我们用 `%x` (十六进制)格式打印同一个内存数据 `11111111 11111111 11111111 00010101` 时,计算机会忠实地把每一位转换成十六进制。
* 每4位二进制转1位十六进制:
* `1111` -> `f`
* `1111` -> `f`
* `1111` -> `f`
* `1111` -> `f`
* `1111` -> `f`
* `1111` -> `f`
* `0001` -> `1`
* `0101` -> `5`
* 所以合起来就是 `0xffffff15`。`%x` 格式打印时会省略前面的 `0x`,所以输出 `ffffff15`。
**总结一下你的误区:**
你把 `234` 当成了一个纯粹的数学上的二进制数 `11101010`(8位),并在这个基础上进行运算。
但在C程序中,`234` 是存储在一个 **32位的 int 容器** 里的。所有的位运算都是针对这个完整的32位容器进行的。
如果你想得到你预想中的“对8位数据取反”的效果,你需要使用位数明确的类型,并做掩码处理,例如:
- #include "stdio.h"
- main()
- {
- unsigned char a, b; // 使用8位无符号字符类型
- a = 234;
- b = ~a; // 对8位取反
- printf("The a's 1 complement(decimal) is %d \n", b); // 输出 21
- printf("The a's 1 complement(hexidecimal) is %x \n", b); // 输出 15
- }
复制代码
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。 |
|