为什么 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
但为什么首先会出现非直觉行为?
当您将 ~
运算符应用于 x1
和 x2
时,这些值将首先进行整数提升,因为 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
)是“任何尺寸都适合您 运行 使用的机器”并且 char
或 short
都可以用于将内容存储在内存中,但是,一旦将它们从内存加载到处理器寄存器中,C 就可以像 int
.
一样处理它们
这简化了早期 C 编译器的开发。编译器不必通过执行 32 位补码指令后跟 AND 指令来删除不需要的高位来实现您的补码。它只做了一个普通的 32 位补码。
今天我们可以以不同的方式开发语言,但 C 背负着这种遗留问题。
我们以下面两个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
但为什么首先会出现非直觉行为?
当您将 ~
运算符应用于 x1
和 x2
时,这些值将首先进行整数提升,因为 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
)是“任何尺寸都适合您 运行 使用的机器”并且 char
或 short
都可以用于将内容存储在内存中,但是,一旦将它们从内存加载到处理器寄存器中,C 就可以像 int
.
这简化了早期 C 编译器的开发。编译器不必通过执行 32 位补码指令后跟 AND 指令来删除不需要的高位来实现您的补码。它只做了一个普通的 32 位补码。
今天我们可以以不同的方式开发语言,但 C 背负着这种遗留问题。