你只需要取两个的补码
x = -x;
无论 x 是有符号还是无符号,它都有效
为什么?因为您所做的本质上是将数字转换为 2 的补码的快速方法
手动将二进制数转换为其二进制补码的捷径是从最低有效位(LSB) 开始,然后复制所有零(从 LSB 到最高有效位)直到达到第一个 1;然后复制那个 1,并翻转所有剩余的位
https://en.wikipedia.org/wiki/Two%27s_complement#Working_from_LSB_towards_MSB
您只有一位 set,因此当您复制所有零位并反转剩余的零位时,您会得到其 2 的补码。您可以在示例中看到它:00001000 = 8, 11111000 = -8
. 其他一些例子:
00010000 = 16, 11110000 = -16
00100000 = 32, 11100000 = -32
01000000 = 64, 11000000 = -64
如果 x 是有符号类型,那么它很容易理解。在无符号类型的情况下,显然没有负值,因此它基于C 标准如何定义无符号操作来工作
涉及无符号操作数的计算永远不会溢出,因为无法由结果无符号整数类型表示的结果会以比结果类型可以表示的最大值大一的数字为模减少。
这只是2 的补码的另一种定义,因为大于可以由结果类型(即在这种情况下)表示的最大值的一个是 2 N。对无符号值求反总是会在 C 中产生其二进制补码,即使有符号类型是符号幅度或一个补码UINTN_MAX + 1
当然,x = -(int32_t)x;
如果您想输入更多内容,也可以将其转换为有符号类型。你还有另一个解决方案
x = ~x + 1; // by 2's complement definition
一个易于理解的解决方案
while (!(x & 0x80000000))
x |= x << 1;
这段代码不需要像上面的许多解决方案一样一直循环 32 次