让我们举例说明以下两个1字节变量:
uint8_t x1 = 0x00;
uint8_t x2 = 0xFF;
打印按位补码时,结果为4字节变量:
printf("%02X -> %02X; %02X -> %02X\n", x1, ~x1, x2, ~x2);
00 -> FFFFFFFF; FF -> FFFFFF00
我知道这可以解决"使用铸造或掩蔽:
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
但为什么首先出现非直觉行为?
答案 0 :(得分:2)
许多计算机处理器的大多数操作都具有“字”大小。例如,在32位机器上,可能存在加载32位的指令,存储32位的指令,将一个32位数加到另一位的指令,等等。
在这些处理器上,使用其他尺寸可能会令人讨厌。可能没有将16位数乘以另一个16位数的指令。 C在这些机器上长大。它的设计是为了int
(或unsigned int
)“无论大小对你正在运行的机器有什么好处”,char
或short
都适合存放内存,但是,一旦它们从内存加载到处理器寄存器中,C就像它们int
一样使用它们。
这简化了早期C编译器的开发。编译器不必通过执行32位补码指令,然后执行AND指令来删除不需要的高位来实现补码。它只做了一个简单的32位补码。
我们今天可以用不同的方式开发语言,但C承担着这种遗产。
答案 1 :(得分:1)
当您将~
运算符应用于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);