【问题标题】:What is the difference between signed and unsigned int有符号整数和无符号整数有什么区别
【发布时间】:2011-08-10 00:57:17
【问题描述】:

signed int 和 unsigned int 有什么区别?

【问题讨论】:

  • 这是一个真实的问题,答案不是那么简单,而是很微妙。
  • 投票重新开放。它可能是重复的,但它绝对是一个真实的问题。
  • 应该添加更多标签,因为许多语言都使用它们。
  • 这个问题可能需要一章来阐述。如果你想知道来龙去脉,请查看Unsigned and Signed Integers以获得更多解释。

标签: c unsigned-integer signed-integer


【解决方案1】:

您可能知道,ints 在内部以二进制形式存储。通常,int 包含 32 位,但在某些环境中可能包含 16 或 64 位(甚至是不同的数字,通常但不一定是 2 的幂)。

但是对于这个例子,让我们看一下 4 位整数。很小,但对插图很有用。

由于这样一个整数有四位,它可以假设 16 个值之一; 16 是 2 的 4 次方,或 2 次 2 次 2 次 2。这些值是多少?答案取决于这个整数是signed int 还是unsigned int。使用unsigned int,该值永远不会是负数;没有与该值关联的符号。以下是四位 unsigned int 的 16 个可能值:

bits  value
0000    0
0001    1
0010    2
0011    3
0100    4
0101    5
0110    6
0111    7
1000    8
1001    9
1010   10
1011   11
1100   12
1101   13
1110   14
1111   15

... 以下是四位 signed int 的 16 个可能值:

bits  value
0000    0
0001    1
0010    2
0011    3
0100    4
0101    5
0110    6
0111    7
1000   -8
1001   -7
1010   -6
1011   -5
1100   -4
1101   -3
1110   -2
1111   -1

如您所见,对于signed ints,当且仅当数字为负时,最高有效位为1。这就是为什么对于signed ints,这个位被称为“符号位”。

【讨论】:

  • 也许值得指出的是,这是二进制补码格式,目前公认它已被广泛使用。还有其他表示有符号整数的方法,最显着的是反码。
  • 正确。而 ISO9899 C 标准甚至不要求使用一个补码或二进制补码;任何其他实际有效的约定都是允许的。
  • 虽然不需要二进制补码,但(unsigned)(-1) 必须是unsigned 的最大可表示值(独立于二进制表示),这对于 2 的补码来说很简单,但对于其他表示则不然.
  • @BillEvansatMariposa:标准规定对于有符号整数有 3 种允许的表示形式:符号+幅度、2 的补码、1 的补码。任何其他都必须对程序不可见,并被视为这 3 种之一。
  • 好的,但在引擎盖下!真正发生了什么!有符号数和无符号数有什么区别!机器如何管理计算?它只是从另一个值中减去一个值? 1111 = 15 和 1111 = -1 有何区别?
【解决方案2】:

用外行的话来说,unsigned int 是一个不能为负的整数,因此它可以假设的正值范围更大。带符号的 int 是一个整数,可以为负数,但具有较低的正数范围以换取它可以假设的更多负值。

【讨论】:

  • 有时像这样的简单答案可以很好地解释这一点。
【解决方案3】:

intunsigned int 是两种不同的整数类型。 (int也可以简称为signed int,或者只是signedunsigned int也可以简称为unsigned。)

顾名思义,int 是一个有符号 整数类型,unsigned int 是一个无符号 整数类型。这意味着int 可以表示负值,而unsigned int 只能表示非负值。

C 语言对这些类型的范围提出了一些要求。 int 的范围必须至少为-32767 ..+32767unsigned int 的范围必须至少为0 ..65535。这意味着两种类型都必须至少为 16 位。它们在许多系统上是 32 位,在某些系统上甚至是 64 位。由于大多数现代系统使用二进制补码表示,int 通常具有额外的负值。

也许最重要的区别是有符号和无符号算术的行为。对于签名的int,溢出具有未定义的行为。对于unsigned int,没有溢出;任何产生超出类型范围的值的操作都会回绕,例如UINT_MAX + 1U == 0U

任何整数类型,无论是有符号的还是无符号的,都对无限的数学整数集的一个子范围进行建模。只要您使用类型范围内的值,一切正常。当您接近一个类型的下限或上限时,您会遇到不连续性,并且可能会得到意想不到的结果。对于有符号整数类型,只有非常大的负值和正值才会出现问题,超过 INT_MININT_MAX。对于无符号整数类型,非常大的正值和零会出现问题。这可能是错误的来源。例如,这是一个无限循环:

for (unsigned int i = 10; i >= 0; i --) [
    printf("%u\n", i);
}

因为i总是大于或等于零;这就是无符号类型的本质。 (在循环内部,当i 为零时,i-- 将其值设置为UINT_MAX。)

【讨论】:

    【解决方案4】:

    有时我们提前知道存储在给定整数变量中的值将始终为正值——例如,当它仅用于计数时。在这种情况下,我们可以将变量声明为无符号,如unsigned int num student;。通过这样的声明,允许的整数值的范围(对于 32 位编译器)将从 -2147483648 到 +2147483647 的范围转移到 0 到 4294967295 的范围。因此,将整数声明为无符号整数几乎会使可能的最大值的大小翻倍否则它可以保持的值。

    【讨论】:

    • @Alex 我 10 分钟前正在编辑那个答案,它是相同的。大声笑
    【解决方案5】:

    在实践中,有两个区别:

    1. 打印(例如,在 C++ 中使用 cout 或在 C 中使用 printf):打印函数将无符号整数位表示解释为非负整数。
    2. 排序:排序取决于有符号或无符号规范。

    此代码可以使用排序标准识别整数:

    char a = 0;
    a--;
    if (0 < a)
        printf("unsigned");
    else
        printf("signed");
    

    char 在某些编译器中被视为 signed,在其他编译器中被视为 unsigned。上面的代码使用排序标准确定在编译器中考虑哪一个。如果a 是无符号的,在a-- 之后,它将大于0,但如果是signed,它将小于零。但在这两种情况下,a 的位表示是相同的。也就是说,在这两种情况下,a-- 都会对位表示进行相同的更改。

    【讨论】:

    • 如果这解释了一个处理负数而另一个处理负数的不同之处,则不是。这将对这篇文章有很大帮助。
    • @DanielJackson 不清楚你在说什么。一个 char 可以被认为是负数或正数,具体取决于编译器。代码的输出取决于编译器选择的内容,这显示了有符号和无符号之间的区别。
    猜你喜欢
    • 2013-10-02
    • 2017-06-07
    • 2015-02-17
    • 1970-01-01
    • 1970-01-01
    • 2010-09-19
    • 2022-01-20
    • 1970-01-01
    相关资源
    最近更新 更多