有符号整型和无符号整型的区别是什么

有符号整型和无符号整型的区别是什么?

173195 次浏览

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

但是对于这个例子,让我们看看4位整数。很小,但是对于演示来说很有用。

因为这样一个整数有四个位,所以它可以假定16个值中的一个; 16是2的四次方,或者2乘2乘2乘2。这些价值观是什么?答案取决于这个整数是 signed int还是 unsigned int。对于 unsigned int,该值永远不会为负; 没有与该值相关联的符号。下面是4位 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

下面是4位 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 int,最有效的位是 1当且仅当数字为负。这就是为什么对于 signed int来说,这个位被称为“符号位”。

有时我们事先知道存储在给定整数变量中的值总是正的——例如,当它被用来只计数时。在这种情况下,我们可以将变量声明为无符号的,如 unsigned int num student;。使用这样的声明,允许的整数值范围(对于32位编译器)将从 -2147483648到 + 2147483647到0到4294967295。因此,将一个整数声明为无符号的几乎是它可以保存的最大值大小的两倍。

在外行人的术语中,一个无符号整数是一个不能为负的整数,因此它可以假设一个更大的正值范围。有符号整数是一个整数,它可以是负数,但是具有较低的正值范围,以换取它可以假设的更多负值。

intunsigned int是两种不同的整数类型。(int也可以被称为 signed int,或者仅仅是 signed; unsigned 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。)

在实践中,存在两个不同之处:

  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--对位表示进行相同的更改。