0

我查找的所有内容都只是告诉我如何在 C 中进行补码运算/计算。

我想知道 C 在内部使用什么表示以及它如何处理溢出。

4

3 回答 3

5

C 允许有符号整数的 3 种表示形式(https://port70.net/~nsz/c/c11/n1570.html#6.2.6.2p2):

  • 符号位为 0 的对应值取反(符号和幅度);
  • 符号位的值为 -(2M)(二进制补码);
  • 符号位的值为 -(2M- 1) (反码)。

二进制补码是最常见的。

无符号溢出环绕无符号的最大值。

有符号溢出会导致未定义的行为。即,假设它不会发生,并且如果您确实发生了,则无法保证您的程序的行为。

签名原子中的溢出是一个例外:它定义明确,并且在那里强制要求补码:https ://port70.net/~nsz/c/c11/n1570.html#7.17.7.5p3 。

于 2021-07-05T11:40:42.410 回答
1

C 是否对负整数使用一个补码、二进制补码或符号/大小表示是实现定义的。也就是说,每个编译器都可以选择,通常基于它为其生成代码的处理器。

所以当你写

x = -x

编译器可能会生成相当于

x = ~x;            /* one's complement */

或者

x = ~x + 1;        /* two's complement */

或者

x ^= 0x80000000;   /* sign/magnitude, assuming 32 bits */

当然,大多数时候您不必担心这一点。(而且大多数时候——现在可以肯定地说,一直都是——你在使用二进制补码的机器上工作,因为它是最受欢迎的。)

由于它是定义的实现,文档应该告诉你。但我想你总是可以用一段代码凭经验确定它:

#include <stdio.h>
#include <limits.h>

int main()
{
    int x = 1;
    int negativex = -x;
    if(negativex == ~x)
         printf("one's complement\n");
    else if(negativex == ~x + 1)
         printf("two's complement\n");
    else if(negativex == (x ^ (1 << (sizeof(x) * CHAR_BIT - 1))))
         printf("sign/magnitude\n");
    else
         printf("what the heck kind of machine are you on??\n");
}

你问过溢出。对于无符号整数,溢出以明显的方式定义为“环绕”(即,它以 2^N 为模执行,其中 N 是位数)。但是对于有符号整数,溢出在形式上是未定义的:理论上可能存在有符号整数溢出产生错误的机器,或多或少类似于除以 0。

(当然,在普通的二进制补码机器上,有符号整数算术也以明显的方式悄悄地环绕,因为二进制补码的全部意义在于环绕溢出使其工作。)

于 2021-07-05T11:39:06.697 回答
-2

简而言之,我们可以说 C 中的2s 补码被定义为 C 中的 1 的补码与 1 之和。

C 中的2s 补码是从 C 中的 1s 补码生成的。众所周知,二进制数的 1s 补码是通过将位 1 转换为 0 和 0 转换为 1 来创建的。二进制数的 2s 补码是通过将二进制数的 1s 补码加 1 生成的。

于 2021-07-05T11:38:28.743 回答