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

时间:2014-10-31 10:57:31

标签: 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;
}

输出:

Int(35d)=35
Int(-35d)=-35
UInt(35u)=35
UInt(-35u)=4294967261
UInt(-35d)=-35
SInt(-35u)=4294967261

如果我将值声明为signed或unsigned int,这真的很重要吗?因为,C实际上只关心我如何从内存中读取值。请帮助我理解这一点,我希望你证明我错了。

5 个答案:

答案 0 :(得分:4)

unsigned intsigned int在内存中占用相同的字节数。它们可以存储相同的字节值。但是,数据的处理方式会有所不同,具体取决于是签名还是未签名。

有关表示整数值的最常用方法的说明,请参阅http://en.wikipedia.org/wiki/Two%27s_complement

由于您可以在C中进行类型转换,因此可以有效地强制编译器将unsigned int视为signed int,反之亦然,但要注意它并不意味着它会按照您的想法执行或表示将是正确的。 (溢出有符号整数会调用C中的未定义行为。)

(正如评论中所指出的,除了两个补码之外,还有其他方式来表示整数,但是在桌面计算机上最常用的是两个补码。)

答案 1 :(得分:3)

  

如果我将值声明为signed或unsigned int,那真的很重要吗?

例如,看看

#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);
}

及其输出

1.333333
1.000000
-0.000000
-1431655764.000000

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

答案 2 :(得分:3)

Representation of signed integers取决于底层平台,而不是C语言本身。对于有符号整数表示,语言定义主要是不可知的。 Two's complement可能是最常见的,但还有其他表示形式,例如one's complementsigned magnitude

在双补码系统中,您通过反转位并添加1来否定一个值。要从5转到-5,您可以执行以下操作:

5 == 0101 => 1010 + 1 == 1011 == -5

要从-5返回5,请按照相同的步骤操作:

-5 == 1011 => 0100 + 1 == 0101 == 5
  

如果我将值声明为signed或unsigned int,那真的很重要吗?

是的,原因如下:

  1. 它会影响您可以表示的值:无符号整数可以表示从02N-1的值,而有符号整数可以表示-2N-12N-1-1之间的值(两个补充)。

  2. 对于无符号整数,溢出是明确定义的; UINT_MAX + 1将&#34;包裹&#34;回到0。对于有符号整数,溢出定义良好,INT_MAX + 1 可以&#34;换行&#34;到INT_MIN,或者可能不是。

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

答案 3 :(得分:1)

#include <stdio.h>

int main(){
    int x = 35, y = -35;
    unsigned int z = 35, p = -35;
    signed int q = -35;

    printf("x=%d\tx=%u\ty=%d\ty=%u\tz=%d\tz=%u\tp=%d\tp=%u\tq=%d\tq=%u\t",x,x,y,y,z,z,p,p,q,q);
}

结果是: x = 35 x = 35 y = -35 y = 4294967261 z = 35 z = 35 p = -35 p = 4294967261 q = -35 q = 4294967261

int数字存储没有区别,它与补充样式存储在内存中,

我可以使用0X ... 0X00000023中的35和0Xffffffd中的-35,使用sigend或unsigend没有区别。它只输出不同的风格。 %d和%u关于正数没有差异,但是负数第一个位置是符号,如果输出%u是0Xffffffdd等于4294967261,但%d 0Xffffffdd可以是 - 0X00000023等于-35。

答案 4 :(得分:-1)

变量类型定义的最基本的东西是它在内存中的存储方式(即 - 读取和写入)以及如何解释这些位,因此您的语句可被视为“有效”。

您还可以使用转化来查看问题。在无符号变量中存储有符号和负值时,它将转换为无符号。碰巧这种转换是可逆的,因此签名-35转换为无符号4294967261,当你请求时,它可以转换为有符号-35。这就是2的补码编码(见其他答案中的链接)的作用。