为什么 1 字节变量的按位补码 returns 是 4 字节值?

Why bitwise complement of a 1-byte variable returns a 4-byte value?

我们以下面两个1字节的变量为例:

uint8_t x1 = 0x00;
uint8_t x2 = 0xFF;

打印按位补码时,结果是一个4字节的变量:

printf("%02X -> %02X; %02X -> %02X\n", x1, ~x1, x2, ~x2);
00 -> FFFFFFFF; FF -> FFFFFF00

我知道这可以 "solved" 使用转换或掩码:

printf("%02X -> %02X; %02X -> %02X\n", x1, (uint8_t) ~x1, x2, (uint8_t) ~x2);
00 -> FF; FF -> 00
printf("%02X -> %02X; %02X -> %02X\n", x1, ~x1&0xFF, x2, ~x2&0xFF);
00 -> FF; FF -> 00

但为什么首先会出现非直觉行为?

当您将 ~ 运算符应用于 x1x2 时,这些值将首先进行整数提升,因为 uint8_t 小于 int.然后将运算符应用于提升的值。

所以 ~x1 实际上是 ~0x00000000(即 0xFFFFFFFF),而 ~x2 实际上是 ~0x000000FF(即 FFFFFF00)。这就是为什么你得到你得到的价值。

此外,%x 格式说明符需要一个 unsigned int,它会这样打印。

您需要使用 %hhx 作为格式说明符。这表示一个 unsigned char 参数。

printf("%02hhX -> %02hhX; %02hhX -> %02hhX\n", x1, ~x1, x2, ~x2);

许多计算机处理器的大部分操作都有“字”大小。例如,在 32 位机器上,可能有一条加载 32 位的指令,一条存储 32 位的指令,一条将一个 32 位数字与另一个相加的指令,等等。

在这些处理器上,使用其他尺寸可能会很麻烦。可能没有将一个 16 位数字乘以另一个 16 位数字的指令。 C 在这些机器上长大。它的设计使得 int(或 unsigned int)是“任何尺寸都适合您 运行 使用的机器”并且 charshort 都可以用于将内容存储在内存中,但是,一旦将它们从内存加载到处理器寄存器中,C 就可以像 int.

一样处理它们

这简化了早期 C 编译器的开发。编译器不必通过执行 32 位补码指令后跟 AND 指令来删除不需要的高位来实现您的补码。它只做了一个普通的 32 位补码。

今天我们可以以不同的方式开发语言,但 C 背负着这种遗留问题。