C 如何在有符号整数和无符号整数中存储负数?

A6S*_*6SE 5 c int unsigned-integer

这是示例:

#include <stdio.h>

int main()
{
    int x=35;
    int y=-35;
    unsigned int z=35;
    unsigned int p=-35;
    signed int q=-35;
    printf("Int(35d)=%d\n\
Int(-35d)=%d\n\
UInt(35u)=%u\n\
UInt(-35u)=%u\n\
UInt(-35d)=%d\n\
SInt(-35u)=%u\n",x,y,z,p,p,q);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出:

Int(35d)=35
Int(-35d)=-35
UInt(35u)=35
UInt(-35u)=4294967261
UInt(-35d)=-35
SInt(-35u)=4294967261
Run Code Online (Sandbox Code Playgroud)

我将值声明为有符号整数还是无符号整数真的很重要吗?因为,C实际上只关心我如何从内存中读取值。请帮助我理解这一点,我希望你证明我错了。

Joh*_*ode 8

有符号整数的表示取决于底层平台,而不是 C 语言本身。语言定义对于有符号整数表示来说大多是不可知的。 二进制补码可能是最常见的,但还有其他表示形式,例如二进制补码有符号大小

在二进制补码系统中,您可以通过反转位并加 1 来求负一个值。要从 到5-5您需要执行以下操作:

5 == 0101 => 1010 + 1 == 1011 == -5
Run Code Online (Sandbox Code Playgroud)

要从-5返回 到5,请遵循相同的过程:

-5 == 1011 => 0100 + 1 == 0101 == 5
Run Code Online (Sandbox Code Playgroud)

我将值声明为有符号整数还是无符号整数真的很重要吗?

是的,原因如下:

  1. 它会影响您可以表示的值:无符号整数可以表示从0到 的值,而有符号整数可以表示和之间的值(二进制补码)。2N-1-2N-12N-1-1

  2. 对于无符号整数,溢出是明确定义的;UINT_MAX + 1将“换行”回0. 对于有符号整数,溢出没有明确定义,并且INT_MAX + 1 可能“换行”到INT_MIN,也可能不“换行”。

  3. 由于 1 和 2,它会影响算术结果,特别是当您在同一表达式中混合有符号和无符号变量时(在这种情况下,如果存在溢出,结果可能无法很好地定义)。


glg*_*lgl 3

我将值声明为有符号整数还是无符号整数真的很重要吗?

是的。

例如,看看

#include <stdio.h>

int main()
{
    int a = -4;
    int b = -3;
    unsigned int c = -4;
    unsigned int d = -3;
    printf("%f\n%f\n%f\n%f\n", 1.0 * a/b, 1.0 * c/d, 1.0*a/d, 1.*c/b);
}
Run Code Online (Sandbox Code Playgroud)

及其输出

1.333333
1.000000
-0.000000
-1431655764.000000
Run Code Online (Sandbox Code Playgroud)

这清楚地表明,如果我将相同的字节表示解释为有符号或无符号,则会产生巨大的差异。