谁定义了整数的符号反转模式?

Who defines the sign inversion pattern for integers?

二进制补码意味着简单地反转数字 i 的所有位得到 -i-1:

~0 是-1

~01000001 为 10111110

~65为-66

等要切换整数的符号,我必须使用实际的减号。

int i = 65; int j = -i; 
cout << j; // -65

实际行为在哪里定义,谁负责确保遵循二进制补码模式(使数字为负,反转所有位并加 1)?我什至不知道这是硬件操作还是编译器操作。

通常由 CPU 硬件完成。

有些 CPU 有计算负数的指令。在 x86 架构中,它是 NEG 指令。

如果不是,可以使用乘法运算符将数字乘以 -1 来完成。但是很多程序员利用你发现的身份,补数然后加1。见

How to convert a positive number to negative in assembly

原因很简单:与0和加法一致。

您希望加法对正数和负数的处理相同,没有特殊情况...特别是,将 -1 递增 1 必须得到 0。

经典溢出增量产生 0 值的唯一位序列是全 1 位序列。如果你递增 1,你会得到全零。这就是你的 -1:全 1,即 0 的按位求反。 现在我们有(假设 8 位整数,每行递增 1)

-2: 11111110 = ~1
-1: 11111111 = ~0
 0: 00000000 = ~-1
+1: 00000001 = ~-2

如果你不喜欢这种行为,你需要另外处理特殊情况,你会有+0和-0。很可能,这样的 CPU 会慢很多。

如果你的问题是如何

int i = -j;

是否实现,这取决于您的编译器和 CPU 以及优化。通常它会与您指定的其他操作一起优化。但是,如果这最终被执行为

,请不要感到惊讶
int i = 0 - j;

因为这可能需要 1-2 cpu 个滴答来计算(例如,作为一个 XOR 或一个寄存器到自身以获得 0,然后一个 SUB 操作来计算 0-j),它几乎不会成为瓶颈。加载 j 并将结果 i 存储在内存中的某处会花费很多很多。事实上,一些 CPUs (MIPS?) 甚至有一个始终为零的内置寄存器。然后你不需要特殊的否定指令,你只需在通常 1 个滴答中从 $zero 中减去 j。 目前的英特尔 CPUs 据说可以识别这种异或运算并在 0 个滴答中完成它们,并进行寄存器重命名优化(即它们让下一条指令使用一个新的零寄存器)。您在 amd64 上有 neg,但快速 xor rax,rax 在其他情况下也很有用。

C 算法是根据值定义的。当代码为:

int i = 65; 
int j = -i; 

无论位表示形式如何,编译器都会发出为 j 提供 -65 值所需的任何 CPU 指令。

历史上,并非所有系统都使用 2 的补码。 C 编译器会根据 CPU 的功能选择负数系统,从而为目标 CPU 提供最有效的输出。

然而,2 的补码是一个非常常见的选择,因为它会导致最简单的算术算法。例如,相同的指令可用于 + - * 有符号和无符号整数。